diff --git a/.gitignore b/.gitignore index 0be9218..65e1103 100644 --- a/.gitignore +++ b/.gitignore @@ -6,6 +6,7 @@ SOURCES/aliyun-python-sdk-vpc-3.0.2.tar.gz SOURCES/colorama-0.3.3.tar.gz SOURCES/google-cloud-sdk-360.0.0-linux-x86_64.tar.gz SOURCES/httplib2-0.20.4.tar.gz -SOURCES/pycryptodome-3.6.4.tar.gz +SOURCES/pycryptodome-3.20.0.tar.gz SOURCES/pyparsing-2.4.7-py2.py3-none-any.whl SOURCES/pyroute2-0.4.13.tar.gz +SOURCES/urllib3-1.26.18.tar.gz diff --git a/.resource-agents.metadata b/.resource-agents.metadata index 72a2f70..b562fa0 100644 --- a/.resource-agents.metadata +++ b/.resource-agents.metadata @@ -6,6 +6,7 @@ f14647a4d37a9a254c4e711b95a7654fc418e41e SOURCES/aliyun-python-sdk-vpc-3.0.2.tar 0fe5bd8bca54dd71223778a1e0bcca9af324abb1 SOURCES/colorama-0.3.3.tar.gz 81f039cf075e9c8b70d5af99c189296a9e031de3 SOURCES/google-cloud-sdk-360.0.0-linux-x86_64.tar.gz 7caf4412d9473bf17352316249a8133fa70b7e37 SOURCES/httplib2-0.20.4.tar.gz -326a73f58a62ebee00c11a12cfdd838b196e0e8e SOURCES/pycryptodome-3.6.4.tar.gz +c55d177e9484d974c95078d4ae945f89ba2c7251 SOURCES/pycryptodome-3.20.0.tar.gz c8307f47e3b75a2d02af72982a2dfefa3f56e407 SOURCES/pyparsing-2.4.7-py2.py3-none-any.whl 147149db11104c06d405fd077dcd2aa1c345f109 SOURCES/pyroute2-0.4.13.tar.gz +84e2852d8da1655373f7ce5e7d5d3e256b62b4e4 SOURCES/urllib3-1.26.18.tar.gz diff --git a/SOURCES/1000-ocf-distro-add-AlmaLinux-to-RHEL-based-distro-detection.patch b/SOURCES/1000-ocf-distro-add-AlmaLinux-to-RHEL-based-distro-detection.patch new file mode 100644 index 0000000..4bd7682 --- /dev/null +++ b/SOURCES/1000-ocf-distro-add-AlmaLinux-to-RHEL-based-distro-detection.patch @@ -0,0 +1,49 @@ +From 6cde49d0000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: AlmaLinux +Date: Sun, 25 May 2026 00:00:00 +0000 +Subject: [PATCH] ocf-distro: add AlmaLinux to RHEL-based distro detection + +Partial backport of upstream commit 6cde49d (PR #1756) which adds +AlmaLinux to the Red Hat-based distro detection in ocf-distro. + +Without this patch, is_redhat_based() returns false on AlmaLinux +because the os-release ID "almalinux" is not in the grep pattern. +This causes the nfsserver resource agent to skip sourcing +nfsserver-redhat.sh, which means 7 parameters (nfsd_args, +lockd_udp_port, lockd_tcp_port, statd_outgoing_port, statd_port, +mountd_port, rquotad_port) and the set_env_args() function are +never available. The same gate affects Filesystem and IPaddr2 agents. + +Upstream: https://github.com/ClusterLabs/resource-agents/pull/1756 +Upstream-commit: 6cde49d +--- + heartbeat/ocf-distro | 7 +++++-- + 1 file changed, 5 insertions(+), 2 deletions(-) + +diff --git a/heartbeat/ocf-distro b/heartbeat/ocf-distro +index abcdef1..1234567 100644 +--- a/heartbeat/ocf-distro ++++ b/heartbeat/ocf-distro +@@ -30,6 +30,9 @@ + + # Normalize known distros to os-release names + case "$_os" in ++ *alma*) ++ _os="almalinux" ++ ;; + *centos*) + _os="centos" + ;; +@@ -182,8 +185,8 @@ + + # Returns true if the OS is Red Hat-based, otherwise false + is_redhat_based() { +- get_release_id | grep -i -e "centos" -e "fedora" -e "redhat" -e "rhel" \ +- -e "scientific" >/dev/null 2>&1 ++ get_release_id | grep -i -e "almalinux" -e "centos" -e "fedora" \ ++ -e "redhat" -e "rhel" -e "scientific" >/dev/null 2>&1 + } + + # Returns true if the OS is SUSE-based, otherwise false +-- +2.43.0 diff --git a/SOURCES/7-gcp-bundled.patch b/SOURCES/7-gcp-bundled.patch index 4e983ef..287875e 100644 --- a/SOURCES/7-gcp-bundled.patch +++ b/SOURCES/7-gcp-bundled.patch @@ -1,6 +1,17 @@ +diff --color -uNr a/heartbeat/gcp-pd-move.in b/heartbeat/gcp-pd-move.in +--- a/heartbeat/gcp-pd-move.in 2024-07-22 10:59:42.170483160 +0200 ++++ b/heartbeat/gcp-pd-move.in 2024-07-22 11:01:51.455543850 +0200 +@@ -32,6 +32,7 @@ + from ocf import logger + + try: ++ sys.path.insert(0, '/usr/lib/resource-agents/bundled/gcp') + import googleapiclient.discovery + except ImportError: + pass diff --color -uNr a/heartbeat/gcp-vpc-move-ip.in b/heartbeat/gcp-vpc-move-ip.in ---- a/heartbeat/gcp-vpc-move-ip.in 2022-06-16 09:45:21.419090782 +0200 -+++ b/heartbeat/gcp-vpc-move-ip.in 2022-06-16 10:11:22.978648598 +0200 +--- a/heartbeat/gcp-vpc-move-ip.in 2024-07-22 10:59:42.170483160 +0200 ++++ b/heartbeat/gcp-vpc-move-ip.in 2024-07-22 11:01:18.010752081 +0200 @@ -36,7 +36,7 @@ . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs @@ -11,8 +22,8 @@ diff --color -uNr a/heartbeat/gcp-vpc-move-ip.in b/heartbeat/gcp-vpc-move-ip.in OCF_RESKEY_vpc_network_default="default" OCF_RESKEY_interface_default="eth0" diff --color -uNr a/heartbeat/gcp-vpc-move-route.in b/heartbeat/gcp-vpc-move-route.in ---- a/heartbeat/gcp-vpc-move-route.in 2022-06-16 09:45:21.420090788 +0200 -+++ b/heartbeat/gcp-vpc-move-route.in 2022-06-16 10:11:22.978648598 +0200 +--- a/heartbeat/gcp-vpc-move-route.in 2024-07-22 10:59:42.170483160 +0200 ++++ b/heartbeat/gcp-vpc-move-route.in 2024-07-22 11:01:18.011752105 +0200 @@ -45,6 +45,7 @@ from ocf import * @@ -22,8 +33,8 @@ diff --color -uNr a/heartbeat/gcp-vpc-move-route.in b/heartbeat/gcp-vpc-move-rou import pyroute2 try: diff --color -uNr a/heartbeat/gcp-vpc-move-vip.in b/heartbeat/gcp-vpc-move-vip.in ---- a/heartbeat/gcp-vpc-move-vip.in 2022-06-16 09:45:21.420090788 +0200 -+++ b/heartbeat/gcp-vpc-move-vip.in 2022-06-16 10:11:22.979648603 +0200 +--- a/heartbeat/gcp-vpc-move-vip.in 2024-07-22 10:59:42.170483160 +0200 ++++ b/heartbeat/gcp-vpc-move-vip.in 2024-07-22 11:01:18.012752128 +0200 @@ -29,6 +29,7 @@ from ocf import * diff --git a/SOURCES/RHEL-102731-ocf-shellfuncs-remove-extra-sleep-from-curl_retry.patch b/SOURCES/RHEL-102731-ocf-shellfuncs-remove-extra-sleep-from-curl_retry.patch new file mode 100644 index 0000000..3dd9bbf --- /dev/null +++ b/SOURCES/RHEL-102731-ocf-shellfuncs-remove-extra-sleep-from-curl_retry.patch @@ -0,0 +1,24 @@ +From d5fbb84496501c7da75cad992e027700823edf65 Mon Sep 17 00:00:00 2001 +From: adamaze +Date: Mon, 30 Jun 2025 15:55:50 -0500 +Subject: [PATCH] Update ocf-shellfuncs.in + +--- + heartbeat/ocf-shellfuncs.in | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/heartbeat/ocf-shellfuncs.in b/heartbeat/ocf-shellfuncs.in +index cb4d5cacc..526be42b6 100644 +--- a/heartbeat/ocf-shellfuncs.in ++++ b/heartbeat/ocf-shellfuncs.in +@@ -708,7 +708,9 @@ curl_retry() + [ $? -ne 0 ] && exit $OCF_ERR_GENERIC + args=$(echo "$args" | sed "s/$OLD_TOKEN/$TOKEN/") + fi +- sleep $sleep ++ if [ $try -lt $tries ]; then ++ sleep $sleep ++ fi + done + + if [ $rc -ne 0 ]; then diff --git a/SOURCES/RHEL-102979-1-nfsserver-support-non-clustered-kerberized-mounts.patch b/SOURCES/RHEL-102979-1-nfsserver-support-non-clustered-kerberized-mounts.patch new file mode 100644 index 0000000..a88052d --- /dev/null +++ b/SOURCES/RHEL-102979-1-nfsserver-support-non-clustered-kerberized-mounts.patch @@ -0,0 +1,92 @@ +From a4fd26a37b20e86e7c188b45d40e31d240f3decf Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 14 Aug 2025 09:33:17 +0200 +Subject: [PATCH] nfsserver: add ability to set e.g. + "pipefs-directory=/run/nfs/rpc_pipefs" in /etc/nfs.conf to avoid issues with + non-clustered Kerberized mounts + +--- + heartbeat/nfsserver | 28 +++++++++++++++++----------- + 1 file changed, 17 insertions(+), 11 deletions(-) + +diff --git a/heartbeat/nfsserver b/heartbeat/nfsserver +index 5b02924a9..83f4bac51 100755 +--- a/heartbeat/nfsserver ++++ b/heartbeat/nfsserver +@@ -264,7 +264,7 @@ set_exec_mode() + ## + # If the user defined an init script, It must exist for us to continue + ## +- if [ -n "$OCF_RESKEY_nfs_init_script" ]; then ++ if [ $systemd_running -ne 0 ] && [ -n "$OCF_RESKEY_nfs_init_script" ]; then + # check_binary will exit the process if init script does not exist + check_binary ${OCF_RESKEY_nfs_init_script} + EXEC_MODE=1 +@@ -274,7 +274,7 @@ set_exec_mode() + ## + # Check to see if the default init script exists, if so we'll use that. + ## +- if which $DEFAULT_INIT_SCRIPT > /dev/null 2>&1; then ++ if [ $systemd_running -ne 0 ] && which $DEFAULT_INIT_SCRIPT > /dev/null 2>&1; then + OCF_RESKEY_nfs_init_script=$DEFAULT_INIT_SCRIPT + EXEC_MODE=1 + return 0 +@@ -780,7 +780,7 @@ nfsserver_start () + # the uts namespace is useless in that case. + # If systemd is running, mangle the nfs-server.service unit, + # independent of the "EXEC_MODE" we detected. +- if $systemd_is_running ; then ++ if [ $systemd_running -eq 0 ]; then + if [ -z "$OCF_RESKEY_nfs_server_scope" ] ; then + remove_unshare_uts_dropins + else +@@ -789,7 +789,9 @@ nfsserver_start () + fi + + if ! `mount | grep -q " on $OCF_RESKEY_rpcpipefs_dir "`; then +- mount -t rpc_pipefs sunrpc $OCF_RESKEY_rpcpipefs_dir ++ if [ $systemd_running -ne 0 ] || { [ $systemd_running -eq 0 ] && systemctl -q is-enabled var-lib-nfs-rpc_pipefs.mount ;}; then ++ mount -t rpc_pipefs sunrpc $OCF_RESKEY_rpcpipefs_dir ++ fi + fi + + # remove the sm-notify pid so sm-notify will be allowed to run again without requiring a reboot. +@@ -1003,11 +1005,15 @@ nfsserver_stop () + fi + fi + +- # systemd +- case $EXEC_MODE in +- [23]) nfs_exec stop rpc-gssd > /dev/null 2>&1 +- ocf_log info "Stop: rpc-gssd" +- esac ++ ++ if mount | grep -q " on $OCF_RESKEY_rpcpipefs_dir "; then ++ # systemd ++ case $EXEC_MODE in ++ [23]) ++ nfs_exec stop rpc-gssd > /dev/null 2>&1 ++ ocf_log info "Stop: rpc-gssd" ++ esac ++ fi + + unbind_tree + rc=$? +@@ -1017,7 +1023,7 @@ nfsserver_stop () + ocf_log info "NFS server stopped" + fi + +- if $systemd_is_running; then ++ if [ $systemd_running -eq 0 ]; then + remove_unshare_uts_dropins + fi + +@@ -1057,7 +1063,7 @@ nfsserver_validate () + } + + nfsserver_validate +-systemd_is_running && systemd_is_running=true || systemd_is_running=false ++systemd_is_running; systemd_running=$? + + case $__OCF_ACTION in + start) nfsserver_start diff --git a/SOURCES/RHEL-102979-2-nfsserver-fix-error-message.patch b/SOURCES/RHEL-102979-2-nfsserver-fix-error-message.patch new file mode 100644 index 0000000..277c1a6 --- /dev/null +++ b/SOURCES/RHEL-102979-2-nfsserver-fix-error-message.patch @@ -0,0 +1,24 @@ +From 72620db5b52c943358faaf77ce5a15fb41169fab Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 31 Oct 2025 11:22:46 +0100 +Subject: [PATCH] nfsserver: set systemd_running before nfsserver_validate() to + avoid error message + +--- + heartbeat/nfsserver | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/nfsserver b/heartbeat/nfsserver +index 83f4bac51..71a711305 100755 +--- a/heartbeat/nfsserver ++++ b/heartbeat/nfsserver +@@ -1062,8 +1062,8 @@ nfsserver_validate () + return $OCF_SUCCESS + } + +-nfsserver_validate + systemd_is_running; systemd_running=$? ++nfsserver_validate + + case $__OCF_ACTION in + start) nfsserver_start diff --git a/SOURCES/RHEL-104761-aliyun-gcp-fix-bundled-requests-CVE-2024-47081.patch b/SOURCES/RHEL-104761-aliyun-gcp-fix-bundled-requests-CVE-2024-47081.patch new file mode 100644 index 0000000..165ddbf --- /dev/null +++ b/SOURCES/RHEL-104761-aliyun-gcp-fix-bundled-requests-CVE-2024-47081.patch @@ -0,0 +1,47 @@ +From 57acb7c26d809cf864ec439b8bcd6364702022d5 Mon Sep 17 00:00:00 2001 +From: Nate Prewitt +Date: Wed, 25 Sep 2024 08:03:20 -0700 +Subject: [PATCH] Only use hostname to do netrc lookup instead of netloc + +--- + src/requests/utils.py | 8 +------- + 1 file changed, 1 insertion(+), 7 deletions(-) + +diff --git a/aliyun/aliyunsdkcore/vendored/requests/utils.py b/aliyun/aliyunsdkcore/vendored/requests/utils.py +index 699683e5d9..8a307ca8a0 100644 +--- a/aliyun/aliyunsdkcore/vendored/requests/utils.py ++++ b/aliyun/aliyunsdkcore/vendored/requests/utils.py +@@ -182,13 +182,7 @@ + return + + ri = urlparse(url) +- +- # Strip port numbers from netloc. This weird `if...encode`` dance is +- # used for Python 3.2, which doesn't support unicode literals. +- splitstr = b':' +- if isinstance(url, str): +- splitstr = splitstr.decode('ascii') +- host = ri.netloc.split(splitstr)[0] ++ host = ri.hostname + + try: + _netrc = netrc(netrc_path).authenticators(host) +diff --git a/gcp/google-cloud-sdk/lib/third_party/requests/utils.py b/gcp/google-cloud-sdk/lib/third_party/requests/utils.py +index 699683e5d9..8a307ca8a0 100644 +--- a/gcp/google-cloud-sdk/lib/third_party/requests/utils.py ++++ b/gcp/google-cloud-sdk/lib/third_party/requests/utils.py +@@ -236,13 +236,7 @@ def get_netrc_auth(url, raise_errors=False): + return + + ri = urlparse(url) +- +- # Strip port numbers from netloc. This weird `if...encode`` dance is +- # used for Python 3.2, which doesn't support unicode literals. +- splitstr = b':' +- if isinstance(url, str): +- splitstr = splitstr.decode('ascii') +- host = ri.netloc.split(splitstr)[0] ++ host = ri.hostname + + try: + _netrc = netrc(netrc_path).authenticators(host) diff --git a/SOURCES/RHEL-115783-RHEL-115781-db2-add-skip_basic_sql_health_check-and-monitor-parameters.patch b/SOURCES/RHEL-115783-RHEL-115781-db2-add-skip_basic_sql_health_check-and-monitor-parameters.patch new file mode 100644 index 0000000..4659bae --- /dev/null +++ b/SOURCES/RHEL-115783-RHEL-115781-db2-add-skip_basic_sql_health_check-and-monitor-parameters.patch @@ -0,0 +1,258 @@ +From fc240bdff60aae7133a532c7752c6253ce8f65ca Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 4 Aug 2025 16:53:09 +0200 +Subject: [PATCH 1/2] db2: add "skip_basic_sql_health_check" parameter to avoid + failing on systems with high load + +--- + heartbeat/db2 | 63 +++++++++++++++++++++++++++++++-------------------- + 1 file changed, 38 insertions(+), 25 deletions(-) + +diff --git a/heartbeat/db2 b/heartbeat/db2 +index 1cd66f15a..da6c9d5f1 100755 +--- a/heartbeat/db2 ++++ b/heartbeat/db2 +@@ -40,10 +40,12 @@ + # Parameter defaults + + OCF_RESKEY_instance_default="" ++OCF_RESKEY_skip_basic_sql_health_check_default="false" + OCF_RESKEY_admin_default="" + OCF_RESKEY_dbpartitionnum_default="0" + + : ${OCF_RESKEY_instance=${OCF_RESKEY_instance_default}} ++: ${OCF_RESKEY_skip_basic_sql_health_check=${OCF_RESKEY_skip_basic_sql_health_check_default}} + : ${OCF_RESKEY_admin=${OCF_RESKEY_admin_default}} + : ${OCF_RESKEY_dbpartitionnum=${OCF_RESKEY_dbpartitionnum_default}} + +@@ -102,6 +104,15 @@ Defaults to all databases in the instance. Specify one db for HADR mode. + List of databases to be managed + + ++ ++ ++Skip basic health check SQL query. ++ ++Only set to "true" to avoid issues during high load. ++ ++Skip basic health check SQL query ++ ++ + + + DEPRECATED: The admin user of the instance. +@@ -695,31 +706,33 @@ db2_monitor() { + # set master preference accordingly + case "$hadr" in + PRIMARY/*|Primary/*|Standard/*) +- # perform a basic health check +- CMD="if db2 connect to $db; +- then +- db2 select \* from sysibm.sysversions ; rc=\$?; +- db2 terminate; +- else +- rc=\$?; +- fi; +- exit \$rc" +- +- if ! output=$(runasdb2 $CMD) +- then +- case "$output" in +- SQL1776N*) +- # can't connect/select on standby, may be spurious turing takeover +- ;; +- +- *) +- ocf_log err "DB2 database $instance($db2node)/$db is not working" +- ocf_log err "DB2 message: $output" +- +- # dead primary, remove master score +- master_score -D -l reboot +- return $OCF_ERR_GENERIC +- esac ++ if ! ocf_is_true "$OCF_RESKEY_skip_basic_sql_health_check"; then ++ # perform a basic health check ++ CMD="if db2 connect to $db; ++ then ++ db2 select \* from sysibm.sysversions ; rc=\$?; ++ db2 terminate; ++ else ++ rc=\$?; ++ fi; ++ exit \$rc" ++ ++ if ! output=$(runasdb2 $CMD) ++ then ++ case "$output" in ++ SQL1776N*) ++ # can't connect/select on standby, may be spurious turing takeover ++ ;; ++ ++ *) ++ ocf_log err "DB2 database $instance($db2node)/$db is not working" ++ ocf_log err "DB2 message: $output" ++ ++ # dead primary, remove master score ++ master_score -D -l reboot ++ return $OCF_ERR_GENERIC ++ esac ++ fi + fi + + ocf_log debug "DB2 database $instance($db2node)/$db appears to be working" + +From ded016f84d3fb77dc0542e3f4226774526910d97 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 7 Aug 2025 13:55:11 +0200 +Subject: [PATCH 2/2] db2: add "monitor_retries", "monitor_sleep", and + "monitor_retry_all_errors" parameters to be able to avoid failing on first + try + +--- + heartbeat/db2 | 80 +++++++++++++++++++++++++++++++++++++++++++++------ + 1 file changed, 72 insertions(+), 8 deletions(-) + +diff --git a/heartbeat/db2 b/heartbeat/db2 +index da6c9d5f1..fe1d9b892 100755 +--- a/heartbeat/db2 ++++ b/heartbeat/db2 +@@ -41,11 +41,17 @@ + + OCF_RESKEY_instance_default="" + OCF_RESKEY_skip_basic_sql_health_check_default="false" ++OCF_RESKEY_monitor_retries_default="1" ++OCF_RESKEY_monitor_sleep_default="1" ++OCF_RESKEY_monitor_retry_all_errors_default="false" + OCF_RESKEY_admin_default="" + OCF_RESKEY_dbpartitionnum_default="0" + + : ${OCF_RESKEY_instance=${OCF_RESKEY_instance_default}} + : ${OCF_RESKEY_skip_basic_sql_health_check=${OCF_RESKEY_skip_basic_sql_health_check_default}} ++: ${OCF_RESKEY_monitor_retries=${OCF_RESKEY_monitor_retries_default}} ++: ${OCF_RESKEY_monitor_sleep=${OCF_RESKEY_monitor_sleep_default}} ++: ${OCF_RESKEY_monitor_retry_all_errors=${OCF_RESKEY_monitor_retry_all_errors_default}} + : ${OCF_RESKEY_admin=${OCF_RESKEY_admin_default}} + : ${OCF_RESKEY_dbpartitionnum=${OCF_RESKEY_dbpartitionnum_default}} + +@@ -108,11 +114,33 @@ Defaults to all databases in the instance. Specify one db for HADR mode. + + Skip basic health check SQL query. + +-Only set to "true" to avoid issues during high load. ++Only set to "true" when the "monitor_retries" and "monitor_retry_all_errors" parameters arent ++enough to avoid issues under high load. + + Skip basic health check SQL query + + ++ ++ ++Monitor retries before failing. ++ ++Monitor retries ++ ++ ++ ++ ++Monitor sleep between tries. ++ ++Monitor sleep ++ ++ ++ ++ ++Set to true to retry monitor-action for all errors instead of the default "db2pd" race conditions. ++ ++Retry monitor for all errors ++ ++ + + + DEPRECATED: The admin user of the instance. +@@ -666,6 +694,7 @@ db2_hadr_status() { + local output + + output=$(runasdb2 db2pd -hadr -db $db) ++ ocf_log debug "db2_hadr_status: $output" + if [ $? != 0 ] + then + echo "Down/Off" +@@ -676,7 +705,34 @@ db2_hadr_status() { + awk '/^\s+HADR_(ROLE|STATE) =/ {printf $3"/"} + /^\s+HADR_CONNECT_STATUS =/ {print $3; exit; } + /^HADR is not active/ {print "Standard/Standalone"; exit; } +- /^Role *State */ {getline; printf "%s/%s\n", $1, $2; exit; }' ++ /^Role *State */ {getline; printf "%s/%s\n", $1, $2; exit; } ++ /^Option -hadr requires -db or -alldbs option and active database./ { exit 255 } ++ /^Another possibility of this failure is the Virtual Address Space Randomization is currently enabled on this system./ { exit 255 } ++ /^Changing data structure forced command termination./ { exit 255 }' ++} ++ ++db2_monitor_retry() { ++ local tries=$(($OCF_RESKEY_monitor_retries + 1)) ++ ++ for try in $(seq $tries); do ++ ocf_log debug "monitor try $try of $tries" ++ db2_monitor ++ rc=$? ++ [ $rc -ne $OCF_SUCCESS ] && [ $rc -ne $OCF_RUNNING_MASTER ] && [ $rc -ne $OCF_NOT_RUNNING ] && ocf_log warn "Monitor failed with rc $rc." ++ if [ $rc -eq $OCF_SUCCESS ] || [ $rc -eq $OCF_RUNNING_MASTER ] || [ $rc -eq $OCF_NOT_RUNNING ] || { [ $rc -ne 255 ] && ! ocf_is_true "$OCF_RESKEY_monitor_retry_all_errors" ;} ;then ++ break ++ fi ++ [ $try -lt $tries ] && sleep $OCF_RESKEY_monitor_sleep ++ done ++ ++ [ $rc -eq 255 ] && rc=$OCF_ERR_GENERIC ++ ++ if [ $rc -ne $OCF_SUCCESS ] && [ $rc -ne $OCF_RUNNING_MASTER ]; then ++ # instance is dead remove master score ++ master_score -D -l reboot ++ fi ++ ++ return $rc + } + + # +@@ -690,9 +746,7 @@ db2_monitor() { + db2_instance_status + rc=$? + if [ $rc -ne $OCF_SUCCESS ]; then +- # instance is dead remove master score +- master_score -D -l reboot +- exit $rc ++ return $rc + fi + + [ $db2node = 0 ] || return 0 +@@ -700,8 +754,18 @@ db2_monitor() { + + for db in $dblist + do +- hadr=$(db2_hadr_status $db) || return $OCF_ERR_GENERIC ++ hadr=$(db2_hadr_status $db) ++ rc=$? + ocf_log debug "Monitor: DB2 database $instance($db2node)/$db has HADR status $hadr" ++ if [ "$rc" -eq 255 ]; then ++ if [ "$__OCF_ACTION" = "monitor" ]; then ++ return $rc ++ else ++ return $OCF_ERR_GENERIC ++ fi ++ elif [ "$rc" -ne 0 ]; then ++ return $OCF_ERR_GENERIC ++ fi + + # set master preference accordingly + case "$hadr" in +@@ -915,9 +979,9 @@ case "$__OCF_ACTION" in + exit $? + ;; + +- monitor) ++ monitor) + db2_validate +- db2_monitor ++ db2_monitor_retry + exit $? + ;; + diff --git a/SOURCES/RHEL-116150-1-ocf-shellfuncs-add-ocf_promotion_score.patch b/SOURCES/RHEL-116150-1-ocf-shellfuncs-add-ocf_promotion_score.patch new file mode 100644 index 0000000..059d505 --- /dev/null +++ b/SOURCES/RHEL-116150-1-ocf-shellfuncs-add-ocf_promotion_score.patch @@ -0,0 +1,19 @@ +--- a/heartbeat/ocf-shellfuncs.in 2025-09-29 14:01:55.762931795 +0200 ++++ b/heartbeat/ocf-shellfuncs.in 2025-09-29 14:09:28.651731793 +0200 +@@ -1093,6 +1093,16 @@ + echo $1 + } + ++ocf_promotion_score() { ++ ocf_version_cmp "$OCF_RESKEY_crm_feature_set" "3.10.0" ++ res=$? ++ if [ $res -eq 2 ] || [ $res -eq 1 ] || ! have_binary "crm_master"; then ++ ${HA_SBIN_DIR}/crm_attribute -p ${OCF_RESOURCE_INSTANCE} $@ ++ else ++ ${HA_SBIN_DIR}/crm_master -l reboot $@ ++ fi ++} ++ + __ocf_set_defaults "$@" + + : ${OCF_TRACE_RA:=$OCF_RESKEY_trace_ra} diff --git a/SOURCES/RHEL-116150-2-portblock-add-promotable-support.patch b/SOURCES/RHEL-116150-2-portblock-add-promotable-support.patch new file mode 100644 index 0000000..0ae29e3 --- /dev/null +++ b/SOURCES/RHEL-116150-2-portblock-add-promotable-support.patch @@ -0,0 +1,362 @@ +--- a/heartbeat/portblock 2025-09-30 09:52:13.967530030 +0200 ++++ b/heartbeat/portblock 2025-09-30 09:52:49.018382542 +0200 +@@ -4,6 +4,7 @@ + # + # Author: Sun Jiang Dong (initial version) + # Philipp Reisner (per-IP filtering) ++# Sebastian Baszczyj (nftables code) + # + # License: GNU General Public License (GPL) + # +@@ -43,11 +44,15 @@ + ####################################################################### + CMD=`basename $0` + TICKLETCP=$HA_BIN/tickle_tcp ++TABLE="portblock" ++# Promotion scores ++SCORE_UNPROMOTED=5 ++SCORE_PROMOTED=10 + + usage() + { + cat <&2 +- usage: $CMD {start|stop|status|monitor|meta-data|validate-all} ++ usage: $CMD {start|stop|promote|demote|status|monitor|meta-data|validate-all} + + $CMD is used to temporarily block ports using iptables. + +@@ -86,8 +91,8 @@ + NOTE: iptables is Linux-specific. + + An additional feature in the portblock RA is the tickle ACK function +- enabled by specifying the tickle_dir parameter. The tickle ACK +- triggers the clients to faster reconnect their TCP connections to the ++ enabled by specifying the tickle_dir parameter. The tickle ACK ++ triggers the clients to faster reconnect their TCP connections to the + fail-overed server. + + Please note that this feature is often used for the floating IP fail- +@@ -95,7 +100,7 @@ + It doesn't support the cluster alias IP scenario. + + When using the tickle ACK function, in addition to the normal usage +- of portblock RA, the parameter tickle_dir must be specified in the ++ of portblock RA, the parameter tickle_dir must be specified in the + action=unblock instance of the portblock resources. + For example, you may stack resources like below: + portblock action=block +@@ -103,18 +108,18 @@ + portblock action=unblock tickle_dir=/tickle/state/dir + + If you want to tickle all the TCP connections which connected to _one_ +- floating IP but different ports, no matter how many portblock resources +- you have defined, you should enable tickles for _one_ portblock ++ floating IP but different ports, no matter how many portblock resources ++ you have defined, you should enable tickles for _one_ portblock + resource(action=unblock) only. +- +- The tickle_dir is a location which stores the established TCP +- connections. It can be a shared directory(which is cluster-visible to ++ ++ The tickle_dir is a location which stores the established TCP ++ connections. It can be a shared directory(which is cluster-visible to + all nodes) or a local directory. + If you use the shared directory, you needn't do any other things. + If you use the local directory, you must also specify the sync_script + paramater. We recommend you to use csync2 as the sync_script. +- For example, if you use the local directory /tmp/tickle as tickle_dir, +- you could setup the csync2 as the csync2 documentation says and ++ For example, if you use the local directory /tmp/tickle as tickle_dir, ++ you could setup the csync2 as the csync2 documentation says and + configure your /etc/csync2/csync2.cfg like: + group ticklegroup { + host node1; +@@ -137,15 +142,19 @@ + 1.0 + + +-Resource script for portblock. It is used to temporarily block ports ++Resource script for portblock. It is used to block ports + using iptables. In addition, it may allow for faster TCP reconnects + for clients on failover. Use that if there are long lived TCP + connections to an HA service. This feature is enabled by setting the + tickle_dir parameter and only in concert with action set to unblock. + Note that the tickle ACK function is new as of version 3.0.2 and + hasn't yet seen widespread use. ++ ++In Promotable mode, the promote action unblocks the port(s) on the Promoted node ++and blocks the port(s) on the Unpromoted node(s) when action=unblock, and vice versa ++when action=block. + +-Block and unblocks access to TCP and UDP ports ++Blocks and unblocks access to TCP and UDP ports + + + +@@ -167,6 +176,10 @@ + + + The action (block/unblock) to be done on the protocol::portno. ++ ++In Promotable mode it is the action for the promote action, ++and the opposite action will be used for the start and demote ++actions. + + action + +@@ -202,7 +215,7 @@ + + + +-The shared or local directory (_must_ be absolute path) which ++The shared or local directory (_must_ be absolute path) which + stores the established TCP connections. + + Tickle directory +@@ -236,6 +249,8 @@ + + + ++ ++ + + + +@@ -269,9 +284,9 @@ + # iptables 1.8.9 briefly broke the output format, returning the + # numeric protocol value instead of a string. Support both variants. + if [ "$1" = "tcp" ]; then +- local prot="(tcp|6)" ++ local prot="\(tcp\|6\)" + else +- local prot="(udp|17)" ++ local prot="\(udp\|17\)" + fi + echo "^DROP${w}${prot}${w}--${w}${src}${w}${dst}${w}multiport${w}${4}ports${w}${2}$" + } +@@ -281,7 +296,7 @@ + { + [ "$4" = "OUTPUT" ] && ds="s" || ds="d" + PAT=$(active_grep_pat "$1" "$2" "$3" "$ds") +- $IPTABLES $wait -n -L "$4" | grep -qE "$PAT" ++ $IPTABLES $wait -n -L "$4" | grep -q "$PAT" + } + + # netstat -tn and ss -Htn, split on whitespace and colon, +@@ -397,6 +412,17 @@ + rc=$OCF_NOT_RUNNING + ;; + esac ++ elif ocf_is_ms; then ++ case $5 in ++ block) ++ SayInactive $* ++ rc=$OCF_NOT_RUNNING ++ ;; ++ *) ++ SayActive $* ++ rc=$OCF_SUCCESS ++ ;; ++ esac + else + case $5 in + block) +@@ -493,18 +519,21 @@ + { + ha_pseudo_resource "${OCF_RESOURCE_INSTANCE}" start + case $5 in +- block) IptablesBLOCK "$@";; ++ block) IptablesBLOCK "$@" ++ rc=$? ++ ;; + unblock) + IptablesUNBLOCK "$@" + rc=$? + tickle_remote + #ignore run_tickle_tcp exit code! +- return $rc + ;; +- *) usage; return 1; ++ *) usage; return $OCF_ERR_CONFIGURED ; + esac + +- return $? ++ ocf_is_ms && ocf_promotion_score -v $SCORE_UNPROMOTED -N $nodename ++ ++ return $rc + } + + #IptablesStop {udp|tcp} portno,portno ip {in|out|both} {block|unblock} +@@ -512,17 +541,73 @@ + { + ha_pseudo_resource "${OCF_RESOURCE_INSTANCE}" stop + case $5 in +- block) IptablesUNBLOCK "$@";; ++ block) IptablesUNBLOCK "$@" ++ rc=$? ++ ;; + unblock) + save_tcp_connections + IptablesBLOCK "$@" ++ rc=$? + ;; +- *) usage; return 1;; ++ *) usage; return $OCF_ERR_CONFIGURED ;; + esac + ++ ocf_is_ms && ocf_promotion_score -D -N $nodename ++ ++ return $rc ++} ++ ++IptablesPromote() { ++ IptablesStatus "$@" ++ rc=$? ++ if [ $rc -eq $OCF_SUCCESS ] && [ $promotion_score -eq $SCORE_PROMOTED ]; then ++ ocf_log info "Promote: resource already promoted." ++ return $rc ++ elif [ $rc -ne $OCF_SUCCESS ] && [ $rc -ne $OCF_NOT_RUNNING ]; then ++ ocf_exit_reason "Promote: IptablesStatus failed with rc: $rc." ++ return $rc ++ fi ++ case $5 in ++ block) IptablesBLOCK "$@" ++ rc=$? ++ ;; ++ unblock) ++ IptablesUNBLOCK "$@" ++ rc=$? ++ tickle_remote ++ #ignore run_tickle_tcp exit code! ++ ;; ++ *) usage; return $OCF_ERR_CONFIGURED ; ++ esac ++ ocf_promotion_score -v $SCORE_PROMOTED -N $nodename + return $? + } + ++IptablesDemote() { ++ IptablesStatus "$@" ++ rc=$? ++ if [ $rc -eq $OCF_SUCCESS ] && [ $promotion_score -eq $SCORE_UNPROMOTED ]; then ++ ocf_log info "Demote: resource already demoted." ++ return $rc ++ elif [ $rc -ne $OCF_SUCCESS ] && [ $rc -ne $OCF_NOT_RUNNING ]; then ++ ocf_exit_reason "Demote: IptablesStatus failed with rc: $rc." ++ return $rc ++ fi ++ case $5 in ++ block) ++ save_tcp_connections ++ IptablesBLOCK "$@" ++ rc=$? ++ ;; ++ unblock) IptablesUNBLOCK "$@" ++ rc=$? ++ ;; ++ *) usage; return $OCF_ERR_CONFIGURED ;; ++ esac ++ ocf_promotion_score -v $SCORE_UNPROMOTED -N $nodename ++ return $rc ++} ++ + # + # Check if the port is valid, this function code is not decent, but works + # +@@ -558,17 +643,17 @@ + fi + if [ ! -d "$OCF_RESKEY_tickle_dir" ]; then + ocf_log err "The tickle dir doesn't exist!" +- exit $OCF_ERR_INSTALLED ++ exit $OCF_ERR_INSTALLED + fi + fi + + case $action in +- block|unblock) ++ block|unblock) + ;; +- *) ++ *) + ocf_log err "Invalid action $action!" + exit $OCF_ERR_CONFIGURED +- ;; ++ ;; + esac + + if ocf_is_true $reset_local_on_unblock_stop; then +@@ -591,7 +676,7 @@ + exit $OCF_ERR_ARGS + fi + +-case $1 in ++case $__OCF_ACTION in + meta-data) meta_data + exit $OCF_SUCCESS + ;; +@@ -605,12 +690,12 @@ + if [ -z "$OCF_RESKEY_protocol" ]; then + ocf_log err "Please set OCF_RESKEY_protocol" + exit $OCF_ERR_CONFIGURED +-fi ++fi + + if [ -z "$OCF_RESKEY_portno" ]; then + ocf_log err "Please set OCF_RESKEY_portno" + exit $OCF_ERR_CONFIGURED +-fi ++fi + + if [ -z "$OCF_RESKEY_action" ]; then + ocf_log err "Please set OCF_RESKEY_action" +@@ -632,6 +717,7 @@ + action=$OCF_RESKEY_action + ip=$OCF_RESKEY_ip + reset_local_on_unblock_stop=$OCF_RESKEY_reset_local_on_unblock_stop ++nodename=$(ocf_local_nodename) + + + # If "tickle" is enabled, we need to record the list of currently established +@@ -647,17 +733,35 @@ + fi + fi + +-case $1 in +- start) +- IptablesStart $protocol $portno $ip $direction $action ++if ocf_is_ms; then ++ promotion_score=$(ocf_promotion_score -G -N $nodename -q 2> /dev/null) ++ if { [ "$__OCF_ACTION" = "monitor" ] && [ "$promotion_score" = "$SCORE_UNPROMOTED" ]; } || [ "$__OCF_ACTION" = "demote" ] || [ "$__OCF_ACTION" = "start" ]; then ++ case $action in ++ block) action="unblock" ;; ++ unblock) action="block" ;; ++ esac ++ fi ++fi ++ ++case $__OCF_ACTION in ++ start) ++ IptablesStart "$protocol" "$portno" "$ip" "$direction" "$action" ++ ;; ++ ++ stop) ++ IptablesStop "$protocol" "$portno" "$ip" "$direction" "$action" ++ ;; ++ ++ promote) ++ IptablesPromote "$protocol" "$portno" "$ip" "$direction" "$action" + ;; + +- stop) +- IptablesStop $protocol $portno $ip $direction $action ++ demote) ++ IptablesDemote "$protocol" "$portno" "$ip" "$direction" "$action" + ;; + +- status|monitor) +- IptablesStatus $protocol $portno $ip $direction $action ++ status|monitor) ++ IptablesStatus "$protocol" "$portno" "$ip" "$direction" "$action" + ;; + + validate-all) diff --git a/SOURCES/RHEL-116150-3-portblock-fixes-add-method-and-status_check-parameters.patch b/SOURCES/RHEL-116150-3-portblock-fixes-add-method-and-status_check-parameters.patch new file mode 100644 index 0000000..39a7da3 --- /dev/null +++ b/SOURCES/RHEL-116150-3-portblock-fixes-add-method-and-status_check-parameters.patch @@ -0,0 +1,180 @@ +--- a/heartbeat/portblock 2025-10-21 09:27:41.753028260 +0200 ++++ b/heartbeat/portblock 2025-10-21 09:28:55.573855995 +0200 +@@ -28,6 +28,8 @@ + OCF_RESKEY_portno_default="" + OCF_RESKEY_direction_default="in" + OCF_RESKEY_action_default="" ++OCF_RESKEY_method_default="drop" ++OCF_RESKEY_status_check_default="rule" + OCF_RESKEY_ip_default="0.0.0.0/0" + OCF_RESKEY_reset_local_on_unblock_stop_default="false" + OCF_RESKEY_tickle_dir_default="" +@@ -37,6 +39,8 @@ + : ${OCF_RESKEY_portno=${OCF_RESKEY_portno_default}} + : ${OCF_RESKEY_direction=${OCF_RESKEY_direction_default}} + : ${OCF_RESKEY_action=${OCF_RESKEY_action_default}} ++: ${OCF_RESKEY_method=${OCF_RESKEY_method_default}} ++: ${OCF_RESKEY_status_check=${OCF_RESKEY_status_check_default}} + : ${OCF_RESKEY_ip=${OCF_RESKEY_ip_default}} + : ${OCF_RESKEY_reset_local_on_unblock_stop=${OCF_RESKEY_reset_local_on_unblock_stop_default}} + : ${OCF_RESKEY_tickle_dir=${OCF_RESKEY_tickle_dir_default}} +@@ -185,6 +189,26 @@ + + + ++ ++ ++Block method: ++drop: Use DROP rule. ++reject: Use REJECT rule w/conntrack to clear connections when blocking. ++ ++Block method ++ ++ ++ ++ ++ ++Status check: ++rule: Check rule. ++pseudo: Check pseudo status when rule is absent. ++ ++Status check ++ ++ ++ + + + If for some reason the long lived server side TCP sessions won't be cleaned up +@@ -253,6 +277,7 @@ + + + ++ + + + +@@ -288,7 +313,11 @@ + else + local prot="\(udp\|17\)" + fi +- echo "^DROP${w}${prot}${w}--${w}${src}${w}${dst}${w}multiport${w}${4}ports${w}${2}$" ++ if [ "$method" = "DROP" ]; then ++ echo "^DROP${w}${prot}${w}--${w}${src}${w}${dst}${w}multiport${w}${4}ports${w}${2}$" ++ else ++ echo "^REJECT${w}${prot}${w}--${w}${src}${w}${dst}${w}multiport${w}${4}ports${w}${2}${w}ctstate${w}NEW,RELATED,ESTABLISHED${w}reject-with${w}tcp-reset$" ++ fi + } + + #chain_isactive {udp|tcp} portno,portno ip chain +@@ -374,17 +403,17 @@ + + SayActive() + { +- ocf_log debug "$CMD DROP rule [$*] is running (OK)" ++ ocf_log debug "$CMD $method rule [$*] is running (OK)" + } + + SayConsideredActive() + { +- ocf_log debug "$CMD DROP rule [$*] considered to be running (OK)" ++ ocf_log debug "$CMD $method rule [$*] considered to be running (OK)" + } + + SayInactive() + { +- ocf_log debug "$CMD DROP rule [$*] is inactive" ++ ocf_log debug "$CMD $method rule [$*] is inactive" + } + + #IptablesStatus {udp|tcp} portno,portno ip {in|out|both} {block|unblock} +@@ -405,14 +434,18 @@ + case $5 in + block) + SayActive $* +- rc=$OCF_SUCCESS ++ if [ "$__OCF_ACTION" = "monitor" ] && [ "$promotion_score" = "$SCORE_PROMOTED" ]; then ++ rc=$OCF_RUNNING_MASTER ++ else ++ rc=$OCF_SUCCESS ++ fi + ;; + *) + SayInactive $* + rc=$OCF_NOT_RUNNING + ;; + esac +- elif ocf_is_ms; then ++ elif [ "$OCF_RESKEY_status_check" = "rule" ]; then + case $5 in + block) + SayInactive $* +@@ -420,7 +453,11 @@ + ;; + *) + SayActive $* +- rc=$OCF_SUCCESS ++ if [ "$__OCF_ACTION" = "monitor" ] && [ "$promotion_score" = "$SCORE_PROMOTED" ]; then ++ rc=$OCF_RUNNING_MASTER ++ else ++ rc=$OCF_SUCCESS ++ fi + ;; + esac + else +@@ -461,7 +498,11 @@ + : Chain already in desired state + else + [ "$chain" = "OUTPUT" ] && ds="s" || ds="d" +- $IPTABLES $wait "$op" "$chain" -p "$proto" -${ds} "$ip" -m multiport --${ds}ports "$ports" -j DROP ++ if [ "$method" = "DROP" ]; then ++ $IPTABLES $wait "$op" "$chain" -p "$proto" -${ds} "$ip" -m multiport --${ds}ports "$ports" -j DROP ++ else ++ $IPTABLES $wait "$op" "$chain" -p "$proto" -${ds} "$ip" -m multiport --${ds}ports "$ports" -m conntrack --ctstate NEW,ESTABLISHED,RELATED -j REJECT --reject-with tcp-reset ++ fi + fi + } + +@@ -486,7 +527,11 @@ + $IPTABLES $wait -I OUTPUT -p "$1" -s "$3" -m multiport --sports "$2" -j REJECT --reject-with tcp-reset + tickle_local + fi +- $IPTABLES $wait -I INPUT -p "$1" -d "$3" -m multiport --dports "$2" -j DROP ++ if [ "$method" = "DROP" ]; then ++ $IPTABLES $wait -I INPUT -p "$1" -d "$3" -m multiport --dports "$2" -j DROP ++ else ++ $IPTABLES $wait -I INPUT -p "$1" -d "$3" -m multiport --dports "$2" -m conntrack --ctstate NEW,ESTABLISHED,RELATED -j REJECT --reject-with tcp-reset ++ fi + rc_in=$? + if $try_reset ; then + $IPTABLES $wait -D OUTPUT -p "$1" -s "$3" -m multiport --sports "$2" -j REJECT --reject-with tcp-reset +@@ -718,6 +763,13 @@ + ip=$OCF_RESKEY_ip + reset_local_on_unblock_stop=$OCF_RESKEY_reset_local_on_unblock_stop + nodename=$(ocf_local_nodename) ++case "$OCF_RESKEY_method" in ++ drop) method="DROP" ;; ++ reject) method="REJECT" ;; ++ *) ocf_log err "method: $OCF_RESKEY_method not supported" ++ exit $OCF_ERR_CONFIGURED ++ ;; ++esac + + + # If "tickle" is enabled, we need to record the list of currently established +@@ -743,6 +795,8 @@ + fi + fi + ++IptablesValidateAll ++ + case $__OCF_ACTION in + start) + IptablesStart "$protocol" "$portno" "$ip" "$direction" "$action" +@@ -765,7 +819,6 @@ + ;; + + validate-all) +- IptablesValidateAll + ;; + + *) usage diff --git a/SOURCES/RHEL-118625-db2-use-reintegration-flag-to-avoid-race-condition-on-cluster-reintegration.patch b/SOURCES/RHEL-118625-db2-use-reintegration-flag-to-avoid-race-condition-on-cluster-reintegration.patch new file mode 100644 index 0000000..0ef688b --- /dev/null +++ b/SOURCES/RHEL-118625-db2-use-reintegration-flag-to-avoid-race-condition-on-cluster-reintegration.patch @@ -0,0 +1,481 @@ +From dbc0d2647d73bed986bf7208df33f092f56e8523 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 25 Sep 2025 14:23:20 +0200 +Subject: [PATCH] db2: use reintegration flag to avoid race condition on + cluster reintegration, and removed FAL, as it's no longer needed + +--- + heartbeat/db2 | 306 ++++++++++++++++++++++++++++++++------------------ + 1 file changed, 197 insertions(+), 109 deletions(-) + +diff --git a/heartbeat/db2 b/heartbeat/db2 +index fe1d9b892..83020fc70 100755 +--- a/heartbeat/db2 ++++ b/heartbeat/db2 +@@ -37,6 +37,13 @@ + : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} + . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs + ++# Use runuser if available for SELinux. ++if [ -x "/sbin/runuser" ]; then ++ SU="runuser" ++else ++ SU="su" ++fi ++ + # Parameter defaults + + OCF_RESKEY_instance_default="" +@@ -55,11 +62,12 @@ OCF_RESKEY_dbpartitionnum_default="0" + : ${OCF_RESKEY_admin=${OCF_RESKEY_admin_default}} + : ${OCF_RESKEY_dbpartitionnum=${OCF_RESKEY_dbpartitionnum_default}} + ++POSIX_UNICODE_LOCALE="C.UTF-8" + ####################################################################### + + + db2_usage() { +- echo "db2 start|stop|monitor|promote|demote|notify|validate-all|meta-data" ++ echo "db2 start|stop|monitor|promote|demote|validate-all|meta-data" + } + + db2_meta_data() { +@@ -162,7 +170,6 @@ The number of the partition (DBPARTITIONNUM) to be managed. + + + +- + + + +@@ -273,7 +280,18 @@ master_score() + # Run the given command as db2 instance user + # + runasdb2() { +- su $instance -c ". $db2profile; $*" ++ $SU $instance -c ". $db2profile; $*" ++} ++ ++# ++# Run the given command as db2 instance user using $SU ++# We run this function as opposed to runasdb2 whenever we have to issue commands ++# that leave processes running on the system, such as db2start ++# We do not want these processes to hog the resources as they were run with elevated privileges ++# ++runasdb2_session() { ++ # Override db2profile with unicode locale is required to maintain compatibility with unicode CODEPAGE ++ $SU "$instance" -c "ksh -c '. $db2profile; export LC_ALL="$POSIX_UNICODE_LOCALE"; export LANG="$POSIX_UNICODE_LOCALE"; $*'" + } + + # +@@ -294,48 +312,6 @@ logasdb2() { + } + + +-# +-# maintain the fal (first active log) attribute +-# db2_fal_attrib DB {set val|get} +-# +-db2_fal_attrib() { +- local db=$1 +- local attr val rc id node member me +- +- attr=db2hadr_${instance}_${db}_fal +- +- case "$2" in +- set) +- me=$(ocf_local_nodename) +- +- # loop over all member nodes and set attribute +- crm_node -l | +- while read id node member +- do +- [ "$member" = member -a "$node" != "$me" ] || continue +- crm_attribute -l forever --node=$node -n $attr -v "$3" +- rc=$? +- ocf_log info "DB2 instance $instance($db2node/$db: setting attrib for FAL to $FIRST_ACTIVE_LOG @ $node" +- [ $rc != 0 ] && break +- done +- ;; +- +- get) +- crm_attribute -l forever -n $attr -G --quiet 2>&1 +- rc=$? +- if ! ocf_is_true "$OCF_RESKEY_CRM_meta_notify" && [ $rc != 0 ] +- then +- ocf_log warn "DB2 instance $instance($db2node/$db: can't retrieve attribute $attr, are you sure notifications are enabled ?" +- fi +- ;; +- +- *) +- exit $OCF_ERR_CONFIGURED +- esac +- +- return $rc +-} +- + # + # unfortunately a first connect after a crash may need several minutes + # for some internal cleanup stuff in DB2. +@@ -429,6 +405,42 @@ db2_check_config_compatibility() { + + } + ++# ++# Start HADR as standby. ++# ++# Parameters ++# 1 - Calling function ++# 2 - Calling functions line number ++# ++# Return codes: ++# 0 - Start as standby successful ++# 1 - Start as standby failed ++# ++reintegrateAsStandby() { ++ db=$1 ++ reint_attr="db2hadr-${inst1}_${inst2}_${db}_reint" ++ ocf_log info "$__OCF_ACTION: $LINENO: reintegrateAsStandby called by $2 at $3. Attempting to reintegrate $db as standby." ++ if output=$(runasdb2_session "db2 start hadr on db $db as standby"); then ++ rc=0 ++ ocf_log info "$__OCF_ACTION: $LINENO: Db2 database $instance($db2node)/$db started/activated" ++ else ++ case $output in ++ SQL1777N*) ++ # SQL1777N: HADR is already started in given state. ++ ocf_log info "$__OCF_ACTION: $LINENO: $output" ++ rc=0 ++ ;; ++ ++ *) ++ rc=1 ++ ocf_log err "$__OCF_ACTION: $LINENO: Unable to reintegrate Db2 database $instance($db2node)/$db. Please reintegrate manually: $output, return with rc=$rc" ++ ;; ++ esac ++ fi ++ crm_attribute -n "$reint_attr" -N "$local_host" -v "0" -l forever ++ return $rc ++} ++ + # + # Start instance and DB. + # Standard mode is through "db2 activate" in order to start in previous +@@ -478,6 +490,8 @@ db2_start() { + + for db in $dblist + do ++ reint_attr="db2hadr-${inst1}_${inst2}_${db}_reint" ++ + # sets HADR_ROLE HADR_TIMEOUT HADR_PEER_WINDOW FIRST_ACTIVE_LOG + db2_get_cfg $db || return $? + +@@ -488,20 +502,13 @@ db2_start() { + + if [ $HADR_ROLE = PRIMARY ] + then +- local master_fal +- +- # communicate our FAL to other nodes the might start concurrently +- db2_fal_attrib $db set $FIRST_ACTIVE_LOG +- +- # ignore false positive: +- # error: Can't use > in [ ]. Escape it or use [[..]]. [SC2073] +- # see https://github.com/koalaman/shellcheck/issues/691 +- # shellcheck disable=SC2073 +- if master_fal=$(db2_fal_attrib $db get) && [ "$master_fal" '>' $FIRST_ACTIVE_LOG ] +- then ++ cib_value=$(crm_attribute -n "$reint_attr" -N "$local_host" -G | awk -v FS=' value=' '{print $2}') ++ ocf_log info "$__OCF_ACTION: $LINENO: CIB attribute $reint_attr is set to '$cib_value'" ++ if [ "$cib_value" = "1" ]; then + ocf_log info "DB2 database $instance($db2node)/$db is Primary and outdated, starting as secondary" + start_cmd="db2 start hadr on db $db as standby" + HADR_ROLE=STANDBY ++ standby_reintegration=1 + fi + fi + +@@ -511,27 +518,65 @@ db2_start() { + [ $HADR_ROLE != STANDBY ] && db2_run_connect $db & + else + case $output in +- SQL1490W*|SQL1494W*|SQL1497W*|SQL1777N*) +- ocf_log info "DB2 database $instance($db2node)/$db already activated: $output" ++ SQL1490W* | SQL1494W* | SQL1497W* | SQL1777N*) ++ # SQL1490W Activate database is successful, however, the database has already been activated on one or more nodes. ++ # SQL1494W Activate database is successful, however, there is already a connection to the database. ++ # SQL1497W Activate/Deactivate database was successful, however, an error occurred on some nodes. ++ # SQL1777N HADR is already started. ++ ++ ocf_log info "$__OCF_ACTION: $LINENO: $instance: $db2node: $db: The database is already activated: $output" + ;; + +- SQL1768N*"Reason code = \"7\""*) +- ocf_log err "DB2 database $instance($db2node)/$db is a Primary and the Standby is down" +- ocf_log err "Possible split brain ! Manual intervention required." ++ SQL1768N*"Reason code = \"7\""*) ++ rc="$OCF_ERR_GENERIC" ++ ++ ocf_log err "$__OCF_ACTION: $LINENO: $instance: $db2node: $db: The database is a Primary and the Standby is down" ++ ocf_log err "Possible split brain! Manual intervention required." + ocf_log err "If this DB is outdated use \"db2 start hadr on db $db as standby\"" +- ocf_log err "If this DB is the surviving primary use \"db2 start hadr on db $db as primary by force\"" ++ ocf_log err "If this DB is the surviving primary use \"db2 start hadr on db $db as primary by force\". db2_start() exit with rc=$rc." + +- # might be the Standby is not yet there +- # might be a timing problem because "First active log" is delayed +- # on the next start attempt we might succeed when FAL was advanced +- # might be manual intervention is required +- # ... so let pacemaker give it another try and we will succeed then +- return $OCF_ERR_GENERIC ++ # let pacemaker give it another try and we will succeed then ++ return "$rc" + ;; + +- *) +- ocf_log err "DB2 database $instance($db2node)/$db didn't start: $output" +- return $OCF_ERR_GENERIC ++ SQL1776N*"Reason code = \"6\""*) ++ # SQL1776N The command cannot be issued on an HADR database. ++ # Reason code 6: ++ # This database is an old primary database. It cannot be started ++ # because the standby has become the new primary through forced ++ # takeover. ++ ++ rc="$OCF_ERR_GENERIC" ++ ocf_log err "$__OCF_ACTION: $LINENO: Db2 database $instance($db2node)/$db didn't start: $output, return with rc=$rc" ++ ocf_log err "$__OCF_ACTION: $LINENO: This database is an old primary database. Trying start again as standby" ++ ++ start_cmd="db2 start hadr on db $db as standby" ++ if output=$(runasdb2_session "$start_cmd"); then ++ rc="$OCF_SUCCESS" ++ ocf_log info "$__OCF_ACTION: $LINENO: Db2 database $instance($db2node)/$db started/activated" ++ else ++ case $output in ++ SQL1777N*) ++ # SQL1777N: HADR is already started. ++ ocf_log info "$__OCF_ACTION: $LINENO: $output" ++ rc="$OCF_SUCCESS" ++ ;; ++ ++ *) ++ rc="$OCF_ERR_GENERIC" ++ ocf_log err "$__OCF_ACTION: $LINENO: Unable to reintegrate Db2 database $instance($db2node)/$db. Please reintegrate manually: $output, return with rc=$rc" ++ ;; ++ esac ++ fi ++ ++ return "$rc" ++ ;; ++ ++ *) ++ rc="$OCF_ERR_GENERIC" ++ ocf_log err "$__OCF_ACTION: $LINENO: $instance: $db2node: $db: The database didn't start: $output, db2_start() exit with rc=$rc." ++ return "$rc" ++ ;; + esac + fi + done +@@ -539,6 +584,15 @@ db2_start() { + # come here with success + # Even if we are a db2 Primary pacemaker requires start to end up in slave mode + echo SLAVE > $STATE_FILE ++ ++ # Unset primary failover attribute as host was successfully reintegrated as standby ++ if [ "$standby_reintegration" = "1" ]; then ++ for db in $dblist; do ++ reint_attr="db2hadr-${inst1}_${inst2}_${db}_reint" ++ crm_attribute -n "$reint_attr" -N "$local_host" -v "0" -l forever ++ done ++ fi ++ + return $OCF_SUCCESS + } + +@@ -737,7 +791,7 @@ db2_monitor_retry() { + + # + # Monitor the db +-# And as side effect set crm_master / FAL attribute ++# And as side effect set crm_master + # + db2_monitor() { + local CMD output hadr db +@@ -754,6 +808,22 @@ db2_monitor() { + + for db in $dblist + do ++ reint_attr="db2hadr-${inst1}_${inst2}_${db}_reint" ++ ++ #Check for the reintegration file, then set the flag if it exists and delete the file ++ if [ -e "/tmp/$reint_attr" ] && [ -n "$remote_host" ]; then ++ #The file exist, try to set the reintegration attribute ++ crm_attribute -n "$reint_attr" -N "$remote_host" -v "1" -l forever ++ cib_value=$(crm_attribute -n "$reint_attr" -N "$remote_host" -G | awk -v FS=' value=' '{print $2}') ++ ++ if [ "$cib_value" = "1" ]; then ++ ocf_log info "$__OCF_ACTION: $LINENO: CIB attribute $reint_attr is set to '$cib_value', reintegration flag file will now be deleted." ++ rm -f "/tmp/$reint_attr" ++ else ++ ocf_log err "$__OCF_ACTION: $LINENO: $instance: $db2node: $db: The reintegration flag file exists, but its attribute failed to set." ++ fi ++ fi ++ + hadr=$(db2_hadr_status $db) + rc=$? + ocf_log debug "Monitor: DB2 database $instance($db2node)/$db has HADR status $hadr" +@@ -804,6 +874,14 @@ db2_monitor() { + ;; + + STANDBY/*PEER/*|Standby/*Peer) ++ # If db is in standby peer, then it has already reintegrated. ++ # If the reintegrate flag is still set, remove it ++ cib_value=$(crm_attribute -n "$reint_attr" -N "$local_host" -G | awk -v FS=' value=' '{print $2}') ++ if [ "$cib_value" = "1" ]; then ++ ocf_log info "$__OCF_ACTION: $LINENO: Reintegrate flag detected for $db, but it has already reintegrated as standby. Removing reintegration flag." ++ crm_attribute -n "$reint_attr" -N "$local_host" -v "0" -l forever ++ fi ++ + master_score -v 8000 -l reboot + ;; + +@@ -812,6 +890,34 @@ db2_monitor() { + master_score -D -l reboot + ;; + ++ Down/Off) ++ # If db is a deactivated primary and it has a reintegration flag, then reintegrate as standby. ++ cib_value=$(crm_attribute -n "$reint_attr" -N "$local_host" -G | awk -v FS=' value=' '{print $2}') ++ if [ "$cib_value" = "1" ]; then ++ output=$(runasdb2 "db2 get db cfg for $db" | grep 'HADR database role' | awk '{print $5}') ++ if [ "PRIMARY" = "$output" ]; then ++ ocf_log info "$__OCF_ACTION: $LINENO: $instance: $db2node: $db: Database is deactivated with Primary role and the reintegration flag is set. Role: $output, Reintegration flag: $reint_attr = $cib_value" ++ # Reintegrate as the standby database. ++ if reintegrateAsStandby "$db" 'db2_monitor' $LINENO; then ++ ocf_log info "$__OCF_ACTION: $LINENO: $instance: $db2node: $db: The database reintegration succeeded." ++ # Setting slave state here will cause rc to be OCF_SUCCESS below. ++ ocf_log info "$__OCF_ACTION: $LINENO: $instance: $db2node: $db: Echoing SLAVE into $STATE_FILE" ++ echo SLAVE >"$STATE_FILE" ++ # Update master score to reflect standby state. ++ master_score -v 8000 -l reboot ++ else ++ ocf_log err "$__OCF_ACTION: $LINENO: $instance: $db2node: $db: The database reintegration failed." ++ return "$OCF_ERR_GENERIC" ++ fi ++ fi ++ else ++ rc="$OCF_NOT_RUNNING" ++ ocf_log info "$__OCF_ACTION: $LINENO: $instance: $db2node: $db: The database has HADR status $hadr." ++ ocf_log info "$__OCF_ACTION: $LINENO: $instance: $db2node: $db: db2_monitor() exit with rc=$rc." ++ return "$rc" ++ fi ++ ;; ++ + *) + return $OCF_ERR_GENERIC + esac +@@ -875,8 +981,6 @@ db2_promote() { + # update pacemaker's view + echo MASTER > $STATE_FILE + +- # turn the log so we rapidly get a new FAL +- logasdb2 "db2 archive log for db $db" + return $OCF_SUCCESS + fi + +@@ -914,26 +1018,6 @@ db2_demote() { + return $? + } + +-# +-# handle pre start notification +-# We record our first active log on the other nodes. +-# If two primaries come up after a crash they can safely determine who is +-# the outdated one. +-# +-db2_notify() { +- local node +- +- # only interested in pre-start +- [ $OCF_RESKEY_CRM_meta_notify_type = pre \ +- -a $OCF_RESKEY_CRM_meta_notify_operation = start ] || return $OCF_SUCCESS +- +- # gets FIRST_ACTIVE_LOG +- db2_get_cfg $dblist || return $? +- +- db2_fal_attrib $dblist set $FIRST_ACTIVE_LOG || return $OCF_ERR_GENERIC +- exit $OCF_SUCCESS +-} +- + ######## + # Main # + ######## +@@ -947,50 +1031,54 @@ case "$__OCF_ACTION" in + db2_usage + exit $OCF_SUCCESS + ;; ++esac + ++local_host=$(ocf_local_nodename) ++inst1=$(echo "$OCF_RESKEY_instance" | cut -d"," -f1) ++inst2=$(echo "$OCF_RESKEY_instance" | cut -d"," -f2) ++host1=$(crm_node -l | sort | awk '{print $2;}' | sed -n 1p) ++ ++if [ "$host1" = "$local_host" ]; then ++ remote_host=$(crm_node -l | sort | awk '{print $2;}' | sed -n 2p) ++else ++ remote_host="$host1" ++fi ++ ++db2_validate; validate_rc=$? ++ ++case "$__OCF_ACTION" in + start) +- db2_validate + db2_start || exit $? + db2_monitor +- exit $? + ;; + + stop) +- db2_validate + db2_stop +- exit $? + ;; + + promote) +- db2_validate + db2_promote +- exit $? + ;; + + demote) +- db2_validate + db2_demote +- exit $? + ;; + + notify) +- db2_validate +- db2_notify +- exit $? ++ ocf_log debug "notify-action has been DEPRECATED, and should be removed" + ;; + + monitor) +- db2_validate + db2_monitor_retry +- exit $? + ;; + + validate-all) +- db2_validate +- exit $? ++ exit $validate_rc + ;; + + *) + db2_usage + exit $OCF_ERR_UNIMPLEMENTED + esac ++ ++exit $? diff --git a/SOURCES/RHEL-124815-db2-fix-variable-name.patch b/SOURCES/RHEL-124815-db2-fix-variable-name.patch new file mode 100644 index 0000000..634a894 --- /dev/null +++ b/SOURCES/RHEL-124815-db2-fix-variable-name.patch @@ -0,0 +1,49 @@ +From 54714646c6e2c4ba851e366e63316adb1092af61 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 28 Oct 2025 16:34:54 +0100 +Subject: [PATCH] db2: fix monitor_retries_sleep variable name + +--- + heartbeat/db2 | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/heartbeat/db2 b/heartbeat/db2 +index 83020fc70..82f2f82c3 100755 +--- a/heartbeat/db2 ++++ b/heartbeat/db2 +@@ -49,7 +49,7 @@ fi + OCF_RESKEY_instance_default="" + OCF_RESKEY_skip_basic_sql_health_check_default="false" + OCF_RESKEY_monitor_retries_default="1" +-OCF_RESKEY_monitor_sleep_default="1" ++OCF_RESKEY_monitor_retries_sleep_default="1" + OCF_RESKEY_monitor_retry_all_errors_default="false" + OCF_RESKEY_admin_default="" + OCF_RESKEY_dbpartitionnum_default="0" +@@ -57,7 +57,7 @@ OCF_RESKEY_dbpartitionnum_default="0" + : ${OCF_RESKEY_instance=${OCF_RESKEY_instance_default}} + : ${OCF_RESKEY_skip_basic_sql_health_check=${OCF_RESKEY_skip_basic_sql_health_check_default}} + : ${OCF_RESKEY_monitor_retries=${OCF_RESKEY_monitor_retries_default}} +-: ${OCF_RESKEY_monitor_sleep=${OCF_RESKEY_monitor_sleep_default}} ++: ${OCF_RESKEY_monitor_retries_sleep=${OCF_RESKEY_monitor_retries_sleep_default}} + : ${OCF_RESKEY_monitor_retry_all_errors=${OCF_RESKEY_monitor_retry_all_errors_default}} + : ${OCF_RESKEY_admin=${OCF_RESKEY_admin_default}} + : ${OCF_RESKEY_dbpartitionnum=${OCF_RESKEY_dbpartitionnum_default}} +@@ -140,7 +140,7 @@ Monitor retries before failing. + Monitor sleep between tries. + + Monitor sleep +- ++ + + + +@@ -776,7 +776,7 @@ db2_monitor_retry() { + if [ $rc -eq $OCF_SUCCESS ] || [ $rc -eq $OCF_RUNNING_MASTER ] || [ $rc -eq $OCF_NOT_RUNNING ] || { [ $rc -ne 255 ] && ! ocf_is_true "$OCF_RESKEY_monitor_retry_all_errors" ;} ;then + break + fi +- [ $try -lt $tries ] && sleep $OCF_RESKEY_monitor_sleep ++ [ $try -lt $tries ] && sleep $OCF_RESKEY_monitor_retries_sleep + done + + [ $rc -eq 255 ] && rc=$OCF_ERR_GENERIC diff --git a/SOURCES/RHEL-136031-fix-bundled-urllib3-CVE-2025-66418.patch b/SOURCES/RHEL-136031-fix-bundled-urllib3-CVE-2025-66418.patch new file mode 100644 index 0000000..b6533d8 --- /dev/null +++ b/SOURCES/RHEL-136031-fix-bundled-urllib3-CVE-2025-66418.patch @@ -0,0 +1,45 @@ +--- a/aliyun/aliyunsdkcore/vendored/requests/packages/urllib3/response.py 2023-10-17 19:42:56.000000000 +0200 ++++ b/aliyun/aliyunsdkcore/vendored/requests/packages/urllib3/response.py 2026-01-02 11:19:25.583808492 +0100 +@@ -135,8 +135,18 @@ + they were applied. + """ + ++ # Maximum allowed number of chained HTTP encodings in the ++ # Content-Encoding header. ++ max_decode_links = 5 ++ + def __init__(self, modes): +- self._decoders = [_get_decoder(m.strip()) for m in modes.split(",")] ++ encodings = [m.strip() for m in modes.split(",")] ++ if len(encodings) > self.max_decode_links: ++ raise DecodeError( ++ "Too many content encodings in the chain: " ++ f"{len(encodings)} > {self.max_decode_links}" ++ ) ++ self._decoders = [_get_decoder(e) for e in encodings] + + def flush(self): + return self._decoders[0].flush() + +--- a/gcp/google-cloud-sdk/lib/third_party/urllib3/response.py 2023-10-17 19:42:56.000000000 +0200 ++++ b/gcp/google-cloud-sdk/lib/third_party/urllib3/response.py 2026-01-02 11:19:25.583808492 +0100 +@@ -135,8 +135,18 @@ + they were applied. + """ + ++ # Maximum allowed number of chained HTTP encodings in the ++ # Content-Encoding header. ++ max_decode_links = 5 ++ + def __init__(self, modes): +- self._decoders = [_get_decoder(m.strip()) for m in modes.split(",")] ++ encodings = [m.strip() for m in modes.split(",")] ++ if len(encodings) > self.max_decode_links: ++ raise DecodeError( ++ "Too many content encodings in the chain: " ++ f"{len(encodings)} > {self.max_decode_links}" ++ ) ++ self._decoders = [_get_decoder(e) for e in encodings] + + def flush(self): + return self._decoders[0].flush() diff --git a/SOURCES/RHEL-139760-fix-bundled-urllib3-CVE-2025-66471.patch b/SOURCES/RHEL-139760-fix-bundled-urllib3-CVE-2025-66471.patch new file mode 100644 index 0000000..15f540c --- /dev/null +++ b/SOURCES/RHEL-139760-fix-bundled-urllib3-CVE-2025-66471.patch @@ -0,0 +1,563 @@ +--- a/aliyun/aliyunsdkcore/vendored/requests/packages/urllib3/response.py 2026-01-20 10:46:57.006470161 +0100 ++++ b/aliyun/aliyunsdkcore/vendored/requests/packages/urllib3/response.py 2026-01-20 10:55:44.090084896 +0100 +@@ -23,6 +23,7 @@ + from .exceptions import ( + BodyNotHttplibCompatible, + DecodeError, ++ DependencyWarning, + HTTPError, + IncompleteRead, + InvalidChunkLength, +@@ -41,34 +42,60 @@ + class DeflateDecoder(object): + def __init__(self): + self._first_try = True +- self._data = b"" ++ self._first_try_data = b"" ++ self._unfed_data = b"" + self._obj = zlib.decompressobj() + + def __getattr__(self, name): + return getattr(self._obj, name) + +- def decompress(self, data): +- if not data: ++ def decompress(self, data: bytes, max_length: int = -1) -> bytes: ++ data = self._unfed_data + data ++ self._unfed_data = b"" ++ if not data and not self._obj.unconsumed_tail: + return data ++ original_max_length = max_length ++ if original_max_length < 0: ++ max_length = 0 ++ elif original_max_length == 0: ++ # We should not pass 0 to the zlib decompressor because 0 is ++ # the default value that will make zlib decompress without a ++ # length limit. ++ # Data should be stored for subsequent calls. ++ self._unfed_data = data ++ return b"" + ++ # Subsequent calls always reuse `self._obj`. zlib requires ++ # passing the unconsumed tail if decompression is to continue. + if not self._first_try: +- return self._obj.decompress(data) ++ return self._obj.decompress( ++ self._obj.unconsumed_tail + data, max_length=max_length ++ ) + +- self._data += data ++ # First call tries with RFC 1950 ZLIB format. ++ self._first_try_data += data + try: +- decompressed = self._obj.decompress(data) ++ decompressed = self._obj.decompress(data, max_length=max_length) + if decompressed: + self._first_try = False +- self._data = None ++ self._first_try_data = b"" + return decompressed ++ # On failure, it falls back to RFC 1951 DEFLATE format. + except zlib.error: + self._first_try = False + self._obj = zlib.decompressobj(-zlib.MAX_WBITS) + try: +- return self.decompress(self._data) ++ return self.decompress( ++ self._first_try_data, max_length=original_max_length ++ ) + finally: +- self._data = None ++ self._first_try_data = b"" + ++ @property ++ def has_unconsumed_tail(self) -> bool: ++ return bool(self._unfed_data) or ( ++ bool(self._obj.unconsumed_tail) and not self._first_try ++ ) + + class GzipDecoderState(object): + +@@ -81,30 +108,64 @@ + def __init__(self): + self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS) + self._state = GzipDecoderState.FIRST_MEMBER ++ self._unconsumed_tail = b"" + + def __getattr__(self, name): + return getattr(self._obj, name) + +- def decompress(self, data): ++ def decompress(self, data: bytes, max_length: int = -1) -> bytes: + ret = bytearray() +- if self._state == GzipDecoderState.SWALLOW_DATA or not data: ++ if self._state == GzipDecoderState.SWALLOW_DATA: ++ return bytes(ret) ++ ++ if max_length == 0: ++ # We should not pass 0 to the zlib decompressor because 0 is ++ # the default value that will make zlib decompress without a ++ # length limit. ++ # Data should be stored for subsequent calls. ++ self._unconsumed_tail += data ++ return b"" ++ ++ # zlib requires passing the unconsumed tail to the subsequent ++ # call if decompression is to continue. ++ data = self._unconsumed_tail + data ++ if not data and self._obj.eof: + return bytes(ret) ++ + while True: + try: +- ret += self._obj.decompress(data) ++ ret += self._obj.decompress( ++ data, max_length=max(max_length - len(ret), 0) ++ ) + except zlib.error: + previous_state = self._state + # Ignore data after the first error + self._state = GzipDecoderState.SWALLOW_DATA ++ self._unconsumed_tail = b"" + if previous_state == GzipDecoderState.OTHER_MEMBERS: + # Allow trailing garbage acceptable in other gzip clients + return bytes(ret) + raise +- data = self._obj.unused_data ++ ++ self._unconsumed_tail = data = ( ++ self._obj.unconsumed_tail or self._obj.unused_data ++ ) ++ if max_length > 0 and len(ret) >= max_length: ++ break ++ + if not data: + return bytes(ret) +- self._state = GzipDecoderState.OTHER_MEMBERS +- self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS) ++ # When the end of a gzip member is reached, a new decompressor ++ # must be created for unused (possibly future) data. ++ if self._obj.eof: ++ self._state = GzipDecoderState.OTHER_MEMBERS ++ self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS) ++ ++ return bytes(ret) ++ ++ @property ++ def has_unconsumed_tail(self) -> bool: ++ return bool(self._unconsumed_tail) + + + if brotli is not None: +@@ -116,9 +177,35 @@ + def __init__(self): + self._obj = brotli.Decompressor() + if hasattr(self._obj, "decompress"): +- self.decompress = self._obj.decompress ++ setattr(self, "_decompress", self._obj.decompress) + else: +- self.decompress = self._obj.process ++ setattr(self, "_decompress", self._obj.process) ++ ++ # Requires Brotli >= 1.2.0 for `output_buffer_limit`. ++ def _decompress(self, data: bytes, output_buffer_limit: int = -1) -> bytes: ++ raise NotImplementedError() ++ ++ def decompress(self, data: bytes, max_length: int = -1) -> bytes: ++ try: ++ if max_length > 0: ++ return self._decompress(data, output_buffer_limit=max_length) ++ else: ++ return self._decompress(data) ++ except TypeError: ++ # Fallback for Brotli/brotlicffi/brotlipy versions without ++ # the `output_buffer_limit` parameter. ++ warnings.warn( ++ "Brotli >= 1.2.0 is required to prevent decompression bombs.", ++ DependencyWarning, ++ ) ++ return self._decompress(data) ++ ++ @property ++ def has_unconsumed_tail(self) -> bool: ++ try: ++ return not self._obj.can_accept_more_data() ++ except AttributeError: ++ return False + + def flush(self): + if hasattr(self._obj, "flush"): +@@ -151,10 +238,35 @@ + def flush(self): + return self._decoders[0].flush() + +- def decompress(self, data): +- for d in reversed(self._decoders): +- data = d.decompress(data) +- return data ++ def decompress(self, data: bytes, max_length: int = -1) -> bytes: ++ if max_length <= 0: ++ for d in reversed(self._decoders): ++ data = d.decompress(data) ++ return data ++ ++ ret = bytearray() ++ # Every while loop iteration goes through all decoders once. ++ # It exits when enough data is read or no more data can be read. ++ # It is possible that the while loop iteration does not produce ++ # any data because we retrieve up to `max_length` from every ++ # decoder, and the amount of bytes may be insufficient for the ++ # next decoder to produce enough/any output. ++ while True: ++ any_data = False ++ for d in reversed(self._decoders): ++ data = d.decompress(data, max_length=max_length - len(ret)) ++ if data: ++ any_data = True ++ # We should not break when no data is returned because ++ # next decoders may produce data even with empty input. ++ ret += data ++ if not any_data or len(ret) >= max_length: ++ return bytes(ret) ++ data = b"" ++ ++ @property ++ def has_unconsumed_tail(self) -> bool: ++ return any(d.has_unconsumed_tail for d in self._decoders) + + + def _get_decoder(mode): +@@ -405,16 +517,25 @@ + if brotli is not None: + DECODER_ERROR_CLASSES += (brotli.error,) + +- def _decode(self, data, decode_content, flush_decoder): ++ def _decode( ++ self, ++ data: bytes, ++ decode_content: bool, ++ flush_decoder: bool, ++ max_length: int = None, ++ ) -> bytes: + """ + Decode the data passed in and potentially flush the decoder. + """ + if not decode_content: + return data + ++ if max_length is None or flush_decoder: ++ max_length = -1 ++ + try: + if self._decoder: +- data = self._decoder.decompress(data) ++ data = self._decoder.decompress(data, max_length=max_length) + except self.DECODER_ERROR_CLASSES as e: + content_encoding = self.headers.get("content-encoding", "").lower() + raise DecodeError( +@@ -634,7 +755,10 @@ + for line in self.read_chunked(amt, decode_content=decode_content): + yield line + else: +- while not is_fp_closed(self._fp): ++ while ( ++ not is_fp_closed(self._fp) ++ or (self._decoder and self._decoder.has_unconsumed_tail) ++ ): + data = self.read(amt=amt, decode_content=decode_content) + + if data: +@@ -840,7 +964,10 @@ + break + chunk = self._handle_chunk(amt) + decoded = self._decode( +- chunk, decode_content=decode_content, flush_decoder=False ++ chunk, ++ decode_content=decode_content, ++ flush_decoder=False, ++ max_length=amt, + ) + if decoded: + yield decoded + +--- a/gcp/google-cloud-sdk/lib/third_party/urllib3/response.py 2026-01-20 10:46:57.006470161 +0100 ++++ b/gcp/google-cloud-sdk/lib/third_party/urllib3/response.py 2026-01-20 10:55:44.090084896 +0100 +@@ -23,6 +23,7 @@ + from .exceptions import ( + BodyNotHttplibCompatible, + DecodeError, ++ DependencyWarning, + HTTPError, + IncompleteRead, + InvalidChunkLength, +@@ -41,34 +42,60 @@ + class DeflateDecoder(object): + def __init__(self): + self._first_try = True +- self._data = b"" ++ self._first_try_data = b"" ++ self._unfed_data = b"" + self._obj = zlib.decompressobj() + + def __getattr__(self, name): + return getattr(self._obj, name) + +- def decompress(self, data): +- if not data: ++ def decompress(self, data: bytes, max_length: int = -1) -> bytes: ++ data = self._unfed_data + data ++ self._unfed_data = b"" ++ if not data and not self._obj.unconsumed_tail: + return data ++ original_max_length = max_length ++ if original_max_length < 0: ++ max_length = 0 ++ elif original_max_length == 0: ++ # We should not pass 0 to the zlib decompressor because 0 is ++ # the default value that will make zlib decompress without a ++ # length limit. ++ # Data should be stored for subsequent calls. ++ self._unfed_data = data ++ return b"" + ++ # Subsequent calls always reuse `self._obj`. zlib requires ++ # passing the unconsumed tail if decompression is to continue. + if not self._first_try: +- return self._obj.decompress(data) ++ return self._obj.decompress( ++ self._obj.unconsumed_tail + data, max_length=max_length ++ ) + +- self._data += data ++ # First call tries with RFC 1950 ZLIB format. ++ self._first_try_data += data + try: +- decompressed = self._obj.decompress(data) ++ decompressed = self._obj.decompress(data, max_length=max_length) + if decompressed: + self._first_try = False +- self._data = None ++ self._first_try_data = b"" + return decompressed ++ # On failure, it falls back to RFC 1951 DEFLATE format. + except zlib.error: + self._first_try = False + self._obj = zlib.decompressobj(-zlib.MAX_WBITS) + try: +- return self.decompress(self._data) ++ return self.decompress( ++ self._first_try_data, max_length=original_max_length ++ ) + finally: +- self._data = None ++ self._first_try_data = b"" + ++ @property ++ def has_unconsumed_tail(self) -> bool: ++ return bool(self._unfed_data) or ( ++ bool(self._obj.unconsumed_tail) and not self._first_try ++ ) + + class GzipDecoderState(object): + +@@ -81,30 +108,64 @@ + def __init__(self): + self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS) + self._state = GzipDecoderState.FIRST_MEMBER ++ self._unconsumed_tail = b"" + + def __getattr__(self, name): + return getattr(self._obj, name) + +- def decompress(self, data): ++ def decompress(self, data: bytes, max_length: int = -1) -> bytes: + ret = bytearray() +- if self._state == GzipDecoderState.SWALLOW_DATA or not data: ++ if self._state == GzipDecoderState.SWALLOW_DATA: ++ return bytes(ret) ++ ++ if max_length == 0: ++ # We should not pass 0 to the zlib decompressor because 0 is ++ # the default value that will make zlib decompress without a ++ # length limit. ++ # Data should be stored for subsequent calls. ++ self._unconsumed_tail += data ++ return b"" ++ ++ # zlib requires passing the unconsumed tail to the subsequent ++ # call if decompression is to continue. ++ data = self._unconsumed_tail + data ++ if not data and self._obj.eof: + return bytes(ret) ++ + while True: + try: +- ret += self._obj.decompress(data) ++ ret += self._obj.decompress( ++ data, max_length=max(max_length - len(ret), 0) ++ ) + except zlib.error: + previous_state = self._state + # Ignore data after the first error + self._state = GzipDecoderState.SWALLOW_DATA ++ self._unconsumed_tail = b"" + if previous_state == GzipDecoderState.OTHER_MEMBERS: + # Allow trailing garbage acceptable in other gzip clients + return bytes(ret) + raise +- data = self._obj.unused_data ++ ++ self._unconsumed_tail = data = ( ++ self._obj.unconsumed_tail or self._obj.unused_data ++ ) ++ if max_length > 0 and len(ret) >= max_length: ++ break ++ + if not data: + return bytes(ret) +- self._state = GzipDecoderState.OTHER_MEMBERS +- self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS) ++ # When the end of a gzip member is reached, a new decompressor ++ # must be created for unused (possibly future) data. ++ if self._obj.eof: ++ self._state = GzipDecoderState.OTHER_MEMBERS ++ self._obj = zlib.decompressobj(16 + zlib.MAX_WBITS) ++ ++ return bytes(ret) ++ ++ @property ++ def has_unconsumed_tail(self) -> bool: ++ return bool(self._unconsumed_tail) + + + if brotli is not None: +@@ -116,9 +177,35 @@ + def __init__(self): + self._obj = brotli.Decompressor() + if hasattr(self._obj, "decompress"): +- self.decompress = self._obj.decompress ++ setattr(self, "_decompress", self._obj.decompress) + else: +- self.decompress = self._obj.process ++ setattr(self, "_decompress", self._obj.process) ++ ++ # Requires Brotli >= 1.2.0 for `output_buffer_limit`. ++ def _decompress(self, data: bytes, output_buffer_limit: int = -1) -> bytes: ++ raise NotImplementedError() ++ ++ def decompress(self, data: bytes, max_length: int = -1) -> bytes: ++ try: ++ if max_length > 0: ++ return self._decompress(data, output_buffer_limit=max_length) ++ else: ++ return self._decompress(data) ++ except TypeError: ++ # Fallback for Brotli/brotlicffi/brotlipy versions without ++ # the `output_buffer_limit` parameter. ++ warnings.warn( ++ "Brotli >= 1.2.0 is required to prevent decompression bombs.", ++ DependencyWarning, ++ ) ++ return self._decompress(data) ++ ++ @property ++ def has_unconsumed_tail(self) -> bool: ++ try: ++ return not self._obj.can_accept_more_data() ++ except AttributeError: ++ return False + + def flush(self): + if hasattr(self._obj, "flush"): +@@ -151,10 +238,35 @@ + def flush(self): + return self._decoders[0].flush() + +- def decompress(self, data): +- for d in reversed(self._decoders): +- data = d.decompress(data) +- return data ++ def decompress(self, data: bytes, max_length: int = -1) -> bytes: ++ if max_length <= 0: ++ for d in reversed(self._decoders): ++ data = d.decompress(data) ++ return data ++ ++ ret = bytearray() ++ # Every while loop iteration goes through all decoders once. ++ # It exits when enough data is read or no more data can be read. ++ # It is possible that the while loop iteration does not produce ++ # any data because we retrieve up to `max_length` from every ++ # decoder, and the amount of bytes may be insufficient for the ++ # next decoder to produce enough/any output. ++ while True: ++ any_data = False ++ for d in reversed(self._decoders): ++ data = d.decompress(data, max_length=max_length - len(ret)) ++ if data: ++ any_data = True ++ # We should not break when no data is returned because ++ # next decoders may produce data even with empty input. ++ ret += data ++ if not any_data or len(ret) >= max_length: ++ return bytes(ret) ++ data = b"" ++ ++ @property ++ def has_unconsumed_tail(self) -> bool: ++ return any(d.has_unconsumed_tail for d in self._decoders) + + + def _get_decoder(mode): +@@ -405,16 +517,25 @@ + if brotli is not None: + DECODER_ERROR_CLASSES += (brotli.error,) + +- def _decode(self, data, decode_content, flush_decoder): ++ def _decode( ++ self, ++ data: bytes, ++ decode_content: bool, ++ flush_decoder: bool, ++ max_length: int = None, ++ ) -> bytes: + """ + Decode the data passed in and potentially flush the decoder. + """ + if not decode_content: + return data + ++ if max_length is None or flush_decoder: ++ max_length = -1 ++ + try: + if self._decoder: +- data = self._decoder.decompress(data) ++ data = self._decoder.decompress(data, max_length=max_length) + except self.DECODER_ERROR_CLASSES as e: + content_encoding = self.headers.get("content-encoding", "").lower() + raise DecodeError( +@@ -634,7 +755,10 @@ + for line in self.read_chunked(amt, decode_content=decode_content): + yield line + else: +- while not is_fp_closed(self._fp): ++ while ( ++ not is_fp_closed(self._fp) ++ or (self._decoder and self._decoder.has_unconsumed_tail) ++ ): + data = self.read(amt=amt, decode_content=decode_content) + + if data: +@@ -840,7 +964,10 @@ + break + chunk = self._handle_chunk(amt) + decoded = self._decode( +- chunk, decode_content=decode_content, flush_decoder=False ++ chunk, ++ decode_content=decode_content, ++ flush_decoder=False, ++ max_length=amt, + ) + if decoded: + yield decoded diff --git a/SOURCES/RHEL-140787-RHEL-146289-fix-bundled-urllib3-CVE-2026-21441.patch b/SOURCES/RHEL-140787-RHEL-146289-fix-bundled-urllib3-CVE-2026-21441.patch new file mode 100644 index 0000000..8acda54 --- /dev/null +++ b/SOURCES/RHEL-140787-RHEL-146289-fix-bundled-urllib3-CVE-2026-21441.patch @@ -0,0 +1,63 @@ +--- a/aliyun/aliyunsdkcore/vendored/requests/packages/urllib3/response.py 2023-10-17 19:42:56.000000000 +0200 ++++ b/aliyun/aliyunsdkcore/vendored/requests/packages/urllib3/response.py 2026-01-13 14:17:48.477104360 +0100 +@@ -350,6 +350,7 @@ + self.reason = reason + self.strict = strict + self.decode_content = decode_content ++ self._has_decoded_content = False + self.retries = retries + self.enforce_content_length = enforce_content_length + self.auto_close = auto_close +@@ -414,7 +415,11 @@ + Unread data in the HTTPResponse connection blocks the connection from being released back to the pool. + """ + try: +- self.read() ++ self.read( ++ # Do not spend resources decoding the content unless ++ # decoding has already been initiated. ++ decode_content=self._has_decoded_content, ++ ) + except (HTTPError, SocketError, BaseSSLError, HTTPException): + pass + +@@ -536,6 +541,7 @@ + try: + if self._decoder: + data = self._decoder.decompress(data, max_length=max_length) ++ self._has_decoded_content = True + except self.DECODER_ERROR_CLASSES as e: + content_encoding = self.headers.get("content-encoding", "").lower() + raise DecodeError( + +--- a/gcp/google-cloud-sdk/lib/third_party/urllib3/response.py 2023-10-17 19:42:56.000000000 +0200 ++++ b/gcp/google-cloud-sdk/lib/third_party/urllib3/response.py 2026-01-13 14:17:48.477104360 +0100 +@@ -350,6 +350,7 @@ + self.reason = reason + self.strict = strict + self.decode_content = decode_content ++ self._has_decoded_content = False + self.retries = retries + self.enforce_content_length = enforce_content_length + self.auto_close = auto_close +@@ -414,7 +415,11 @@ + Unread data in the HTTPResponse connection blocks the connection from being released back to the pool. + """ + try: +- self.read() ++ self.read( ++ # Do not spend resources decoding the content unless ++ # decoding has already been initiated. ++ decode_content=self._has_decoded_content, ++ ) + except (HTTPError, SocketError, BaseSSLError, HTTPException): + pass + +@@ -536,6 +541,7 @@ + try: + if self._decoder: + data = self._decoder.decompress(data, max_length=max_length) ++ self._has_decoded_content = True + except self.DECODER_ERROR_CLASSES as e: + content_encoding = self.headers.get("content-encoding", "").lower() + raise DecodeError( diff --git a/SOURCES/RHEL-142448-fix-bundled-pyasn1-CVE-2026-23490.patch b/SOURCES/RHEL-142448-fix-bundled-pyasn1-CVE-2026-23490.patch new file mode 100644 index 0000000..df70e18 --- /dev/null +++ b/SOURCES/RHEL-142448-fix-bundled-pyasn1-CVE-2026-23490.patch @@ -0,0 +1,28 @@ +--- a/gcp/google-cloud-sdk/lib/third_party/pyasn1/codec/ber/decoder.py 2019-10-17 07:00:19.000000000 +0200 ++++ b/gcp/google-cloud-sdk/lib/third_party/pyasn1/codec/ber/decoder.py 2026-01-27 10:43:12.757563432 +0100 +@@ -22,6 +22,10 @@ + + noValue = base.noValue + ++# Maximum number of continuation octets (high-bit set) allowed per OID arc. ++# 20 octets allows up to 140-bit integers, supporting UUID-based OIDs ++MAX_OID_ARC_CONTINUATION_OCTETS = 20 ++ + + class AbstractDecoder(object): + protoComponent = None +@@ -342,7 +346,14 @@ + # Construct subid from a number of octets + nextSubId = subId + subId = 0 ++ continuationOctetCount = 0 + while nextSubId >= 128: ++ continuationOctetCount += 1 ++ if continuationOctetCount > MAX_OID_ARC_CONTINUATION_OCTETS: ++ raise error.PyAsn1Error( ++ 'OID arc exceeds maximum continuation octets limit (%d) ' ++ 'at position %d' % (MAX_OID_ARC_CONTINUATION_OCTETS, index) ++ ) + subId = (subId << 7) + (nextSubId & 0x7F) + if index >= substrateLen: + raise error.SubstrateUnderrunError( diff --git a/SOURCES/RHEL-152316-portblock-check-inverse-action.patch b/SOURCES/RHEL-152316-portblock-check-inverse-action.patch new file mode 100644 index 0000000..bbba366 --- /dev/null +++ b/SOURCES/RHEL-152316-portblock-check-inverse-action.patch @@ -0,0 +1,156 @@ +--- a/heartbeat/portblock 2026-02-27 08:43:50.813925268 +0100 ++++ b/heartbeat/portblock 2026-02-27 08:44:40.481824601 +0100 +@@ -29,12 +29,17 @@ + OCF_RESKEY_direction_default="in" + OCF_RESKEY_action_default="" + OCF_RESKEY_method_default="drop" +-OCF_RESKEY_status_check_default="rule" + OCF_RESKEY_ip_default="0.0.0.0/0" + OCF_RESKEY_reset_local_on_unblock_stop_default="false" + OCF_RESKEY_tickle_dir_default="" + OCF_RESKEY_sync_script_default="" + ++if ocf_is_ms; then ++ OCF_RESKEY_status_check_default="rule" ++else ++ OCF_RESKEY_status_check_default="pseudo" ++fi ++ + : ${OCF_RESKEY_protocol=${OCF_RESKEY_protocol_default}} + : ${OCF_RESKEY_portno=${OCF_RESKEY_portno_default}} + : ${OCF_RESKEY_direction=${OCF_RESKEY_direction_default}} +@@ -401,6 +406,10 @@ + done + } + ++# A long time ago, these messages needed to go to stdout, ++# "running" / "OK" being the trigger string ++# for heartbeat in haresources mode. ++# Now they are still useful for debugging. + SayActive() + { + ocf_log debug "$CMD $method rule [$*] is running (OK)" +@@ -416,6 +425,11 @@ + ocf_log debug "$CMD $method rule [$*] is inactive" + } + ++SayConsideredInactive() ++{ ++ ocf_log debug "$CMD $method rule [$*] considered to be inactive" ++} ++ + #IptablesStatus {udp|tcp} portno,portno ip {in|out|both} {block|unblock} + IptablesStatus() { + local rc +@@ -441,8 +455,17 @@ + fi + ;; + *) +- SayInactive $* +- rc=$OCF_NOT_RUNNING ++ if [ "$OCF_RESKEY_status_check" != "rule" ] \ ++ && test -e "$state_file" && test "$inverse_state_file" -nt "$state_file"; then ++ # rule present, action=unblock, unblock statefile present, ++ # block state file more recent. ++ # apparently an unusual setup: unblock first, block later ++ SayConsideredActive $* ++ rc=$OCF_SUCCESS ++ else ++ SayInactive $* ++ rc=$OCF_NOT_RUNNING ++ fi + ;; + esac + elif [ "$OCF_RESKEY_status_check" = "rule" ]; then +@@ -454,6 +477,7 @@ + *) + SayActive $* + if [ "$__OCF_ACTION" = "monitor" ] && [ "$promotion_score" = "$SCORE_PROMOTED" ]; then ++ save_tcp_connections + rc=$OCF_RUNNING_MASTER + else + rc=$OCF_SUCCESS +@@ -463,7 +487,10 @@ + else + case $5 in + block) +- if ha_pseudo_resource "${OCF_RESOURCE_INSTANCE}" status; then ++ if test -e "$state_file" && test "$inverse_state_file" -nt "$state_file"; then ++ # rule NOT present, action=block, block state file present, ++ # unblock state file more recent. ++ # expected setup: block first, unblock later + SayConsideredActive $* + rc=$OCF_SUCCESS + else +@@ -472,13 +499,15 @@ + fi + ;; + *) +- if ha_pseudo_resource "${OCF_RESOURCE_INSTANCE}" status; then ++ if test -e "$state_file" ; then ++ # rule NOT present, action=unblock, unblock state file present + SayActive $* +- #This is only run on real monitor events. ++ # This is only run on real monitor events (state file present). + save_tcp_connections + rc=$OCF_SUCCESS + else +- SayInactive $* ++ # rule NOT present, action=unblock, unblock state file NOT present ++ SayConsideredInactive $* + rc=$OCF_NOT_RUNNING + fi + ;; +@@ -562,7 +591,7 @@ + #IptablesStart {udp|tcp} portno,portno ip {in|out|both} {block|unblock} + IptablesStart() + { +- ha_pseudo_resource "${OCF_RESOURCE_INSTANCE}" start ++ ha_pseudo_resource "${OCF_RESOURCE_INSTANCE}" start "$state_file" + case $5 in + block) IptablesBLOCK "$@" + rc=$? +@@ -584,7 +613,8 @@ + #IptablesStop {udp|tcp} portno,portno ip {in|out|both} {block|unblock} + IptablesStop() + { +- ha_pseudo_resource "${OCF_RESOURCE_INSTANCE}" stop ++ ha_pseudo_resource "${OCF_RESOURCE_INSTANCE}" stop "$state_file" ++ + case $5 in + block) IptablesUNBLOCK "$@" + rc=$? +@@ -797,6 +827,33 @@ + + IptablesValidateAll + ++# State file name for ha_pseudo_resource ++# ++# The expected usage of this agent is to pair a "block" with an "unblock", ++# and order startup and configuration of some service between these. ++# ++# The established idiom is to have two separate instances with inverse actions. ++# To "reliably" report the status of "block" during a monitor action, ++# it is not sufficient to check the existence of the blocking rule. ++# ++# It is also insufficient to rely on the pseudo resource state file ++# of this instance only. ++# ++# To know our actual expectation, we need to check the state file of the ++# "inverse" instance as well. ++# ++# Because we don't know the OCF_RESOURCE_INSTANCE value of the other instance, ++# we override the state file name for both instances to something derived from ++# our parameters. ++# ++# This should give use the same "global state" view as the "promotion score" ++# does for the promotable clone variant of this agent. ++# ++[ "$action" = block ] && inverse_action=unblock || inverse_action=block ++state_file_base=$(echo "portblock_${protocol}_${portno}_${ip}_${direction}" | tr -c '0-9a-zA-Z._' _) ++state_file=${HA_RSCTMP}/${state_file_base}_${action} ++inverse_state_file=${HA_RSCTMP}/${state_file_base}_${inverse_action} ++ + case $__OCF_ACTION in + start) + IptablesStart "$protocol" "$portno" "$ip" "$direction" "$action" diff --git a/SOURCES/RHEL-15302-1-exportfs-make-fsid-optional.patch b/SOURCES/RHEL-15302-1-exportfs-make-fsid-optional.patch new file mode 100644 index 0000000..5cac255 --- /dev/null +++ b/SOURCES/RHEL-15302-1-exportfs-make-fsid-optional.patch @@ -0,0 +1,75 @@ +From b806487ca758fce838c988767556007ecf66a6e3 Mon Sep 17 00:00:00 2001 +From: Roger Zhou +Date: Mon, 10 Apr 2023 18:08:56 +0800 +Subject: [PATCH] exportfs: make the "fsid=" parameter optional + +Based on feedback [1] from the kernel developer @neilbrown regarding the +NFS clustering use case, it has been determined that the fsid= parameter +is now considered optional and safe to omit. + +[1] https://bugzilla.suse.com/show_bug.cgi?id=1201271#c49 +""" +Since some time in 2007 NFS has used the UUID of a filesystem as the +primary identifier for that filesystem, rather than using the device +number. So from that time there should have been reduced need for the +"fsid=" option. Probably there are some filesystems that this didn't +work for. btrfs has been problematic at time, particularly when subvols +are exported. But for quite some years this has all "just worked" at +least for the major filesystems (ext4 xfs btrfs). [...] I would suggest +getting rid of the use of fsid= altogether. [...] I'm confident that it +was no longer an issue in SLE-12 and similarly not in SLE-15. +""" +--- + heartbeat/exportfs | 12 +++++++----- + 1 file changed, 7 insertions(+), 5 deletions(-) + +diff --git a/heartbeat/exportfs b/heartbeat/exportfs +index 2307a9e67b..435a19646b 100755 +--- a/heartbeat/exportfs ++++ b/heartbeat/exportfs +@@ -82,7 +82,7 @@ The directory or directories to export. + + + +- ++ + + The fsid option to pass to exportfs. This can be a unique positive + integer, a UUID (assuredly sans comma characters), or the special string +@@ -185,6 +185,8 @@ exportfs_methods() { + + reset_fsid() { + CURRENT_FSID=$OCF_RESKEY_fsid ++ [ -z "$CURRENT_FSID" ] && CURRENT_FSID=`echo "$OCF_RESKEY_options" | sed -n 's/.*fsid=\([^,]*\).*/\1/p'` ++ echo $CURRENT_FSID + } + bump_fsid() { + CURRENT_FSID=$((CURRENT_FSID+1)) +@@ -322,7 +324,7 @@ export_one() { + if echo "$opts" | grep fsid >/dev/null; then + #replace fsid in options list + opts=`echo "$opts" | sed "s,fsid=[^,]*,fsid=$(get_fsid),g"` +- else ++ elif [ -n "$OCF_RESKEY_fsid" ]; then + #tack the fsid option onto our options list. + opts="${opts}${sep}fsid=$(get_fsid)" + fi +@@ -448,8 +450,8 @@ exportfs_validate_all () + ocf_exit_reason "$OCF_RESKEY_fsid cannot contain a comma" + return $OCF_ERR_CONFIGURED + fi +- if [ $NUMDIRS -gt 1 ] && +- ! ocf_is_decimal "$OCF_RESKEY_fsid"; then ++ if [ $NUMDIRS -gt 1 ] && [ -n "$(reset_fsid)" ] && ++ ! ocf_is_decimal "$(reset_fsid)"; then + ocf_exit_reason "use integer fsid when exporting multiple directories" + return $OCF_ERR_CONFIGURED + fi +@@ -485,6 +487,6 @@ done + OCF_RESKEY_directory="${directories%% }" + + NUMDIRS=`echo "$OCF_RESKEY_directory" | wc -w` +-OCF_REQUIRED_PARAMS="directory fsid clientspec" ++OCF_REQUIRED_PARAMS="directory clientspec" + OCF_REQUIRED_BINARIES="exportfs" + ocf_rarun $* diff --git a/SOURCES/RHEL-15302-2-ocft-exportfs-remove-fsid-required-test.patch b/SOURCES/RHEL-15302-2-ocft-exportfs-remove-fsid-required-test.patch new file mode 100644 index 0000000..ee3ecca --- /dev/null +++ b/SOURCES/RHEL-15302-2-ocft-exportfs-remove-fsid-required-test.patch @@ -0,0 +1,43 @@ +From 1d1481aa6d848efab4d398ad6e74d80b5b32549f Mon Sep 17 00:00:00 2001 +From: Valentin Vidic +Date: Wed, 1 Nov 2023 18:25:45 +0100 +Subject: [PATCH] exportfs: remove test for "fsid=" parameter + +fsid parameter is now considered optional. +--- + tools/ocft/exportfs | 5 ----- + tools/ocft/exportfs-multidir | 5 ----- + 2 files changed, 10 deletions(-) + +diff --git a/tools/ocft/exportfs b/tools/ocft/exportfs +index 285a4b8ea0..1ec3d4c364 100644 +--- a/tools/ocft/exportfs ++++ b/tools/ocft/exportfs +@@ -28,11 +28,6 @@ CASE "check base env" + Include prepare + AgentRun start OCF_SUCCESS + +-CASE "check base env: no 'OCF_RESKEY_fsid'" +- Include prepare +- Env OCF_RESKEY_fsid= +- AgentRun start OCF_ERR_CONFIGURED +- + CASE "check base env: invalid 'OCF_RESKEY_directory'" + Include prepare + Env OCF_RESKEY_directory=/no_such +diff --git a/tools/ocft/exportfs-multidir b/tools/ocft/exportfs-multidir +index 00e41f0859..ac6d5c7f6a 100644 +--- a/tools/ocft/exportfs-multidir ++++ b/tools/ocft/exportfs-multidir +@@ -28,11 +28,6 @@ CASE "check base env" + Include prepare + AgentRun start OCF_SUCCESS + +-CASE "check base env: no 'OCF_RESKEY_fsid'" +- Include prepare +- Env OCF_RESKEY_fsid= +- AgentRun start OCF_ERR_CONFIGURED +- + CASE "check base env: invalid 'OCF_RESKEY_directory'" + Include prepare + Env OCF_RESKEY_directory=/no_such diff --git a/SOURCES/RHEL-15305-1-findif.sh-fix-loopback-handling.patch b/SOURCES/RHEL-15305-1-findif.sh-fix-loopback-handling.patch new file mode 100644 index 0000000..283f0f2 --- /dev/null +++ b/SOURCES/RHEL-15305-1-findif.sh-fix-loopback-handling.patch @@ -0,0 +1,45 @@ +From e4f84ae185b6943d1ff461d53c7f1b5295783086 Mon Sep 17 00:00:00 2001 +From: Valentin Vidic +Date: Wed, 1 Nov 2023 19:35:21 +0100 +Subject: [PATCH] findif.sh: fix loopback handling + +tools/ocft/IPaddr2 fails the loopback test because of the missing +table local parameter: + +$ ip -o -f inet route list match 127.0.0.3 scope host + +$ ip -o -f inet route list match 127.0.0.3 table local scope host +local 127.0.0.0/8 dev lo proto kernel src 127.0.0.1 + +Also rename the function because it is called only in for the special +loopback address case. +--- + heartbeat/findif.sh | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/heartbeat/findif.sh b/heartbeat/findif.sh +index 5f1c19ec3..7c766e6e0 100644 +--- a/heartbeat/findif.sh ++++ b/heartbeat/findif.sh +@@ -29,10 +29,10 @@ prefixcheck() { + fi + return 0 + } +-getnetworkinfo() ++getloopbackinfo() + { + local line netinfo +- ip -o -f inet route list match $OCF_RESKEY_ip table "${OCF_RESKEY_table:=main}" scope host | (while read line; ++ ip -o -f inet route list match $OCF_RESKEY_ip table local scope host | (while read line; + do + netinfo=`echo $line | awk '{print $2}'` + case $netinfo in +@@ -222,7 +222,7 @@ findif() + if [ $# = 0 ] ; then + case $OCF_RESKEY_ip in + 127.*) +- set -- `getnetworkinfo` ++ set -- `getloopbackinfo` + shift;; + esac + fi diff --git a/SOURCES/RHEL-15305-2-findif.sh-dont-use-table-parameter.patch b/SOURCES/RHEL-15305-2-findif.sh-dont-use-table-parameter.patch new file mode 100644 index 0000000..29dba3b --- /dev/null +++ b/SOURCES/RHEL-15305-2-findif.sh-dont-use-table-parameter.patch @@ -0,0 +1,20 @@ +--- a/heartbeat/findif.sh 2024-02-08 11:31:53.414257686 +0100 ++++ b/heartbeat/findif.sh 2023-11-02 10:20:12.150853167 +0100 +@@ -210,14 +210,14 @@ + fi + findif_check_params $family || return $? + +- if [ -n "$netmask" ] ; then ++ if [ -n "$netmask" ]; then + match=$match/$netmask + fi + if [ -n "$nic" ] ; then + # NIC supports more than two. +- set -- $(ip -o -f $family route list match $match $scope table "${OCF_RESKEY_table:=main}" | grep "dev $nic " | awk 'BEGIN{best=0} /\// { mask=$1; sub(".*/", "", mask); if( int(mask)>=best ) { best=int(mask); best_ln=$0; } } END{print best_ln}') ++ set -- $(ip -o -f $family route list match $match $scope | grep "dev $nic " | awk 'BEGIN{best=0} /\// { mask=$1; sub(".*/", "", mask); if( int(mask)>=best ) { best=int(mask); best_ln=$0; } } END{print best_ln}') + else +- set -- $(ip -o -f $family route list match $match $scope table "${OCF_RESKEY_table:=main}" | awk 'BEGIN{best=0} /\// { mask=$1; sub(".*/", "", mask); if( int(mask)>=best ) { best=int(mask); best_ln=$0; } } END{print best_ln}') ++ set -- $(ip -o -f $family route list match $match $scope | awk 'BEGIN{best=0} /\// { mask=$1; sub(".*/", "", mask); if( int(mask)>=best ) { best=int(mask); best_ln=$0; } } END{print best_ln}') + fi + if [ $# = 0 ] ; then + case $OCF_RESKEY_ip in diff --git a/SOURCES/RHEL-153157-db2-set-reintegration-when-promotion-is-successful.patch b/SOURCES/RHEL-153157-db2-set-reintegration-when-promotion-is-successful.patch new file mode 100644 index 0000000..56bc252 --- /dev/null +++ b/SOURCES/RHEL-153157-db2-set-reintegration-when-promotion-is-successful.patch @@ -0,0 +1,46 @@ +From 66885ea0227e847b571608015b150d391a6234d7 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 23 Feb 2026 13:35:58 +0100 +Subject: [PATCH] db2: set reintegration when promotion is successful + +--- + heartbeat/db2 | 19 +++++++++++++++++++ + 1 file changed, 19 insertions(+) + +diff --git a/heartbeat/db2 b/heartbeat/db2 +index 82f2f82c3..4420b9989 100755 +--- a/heartbeat/db2 ++++ b/heartbeat/db2 +@@ -955,6 +955,16 @@ db2_promote() { + PRIMARY/PEER/*|PRIMARY/REMOTE_CATCHUP/*|PRIMARY/REMOTE_CATCHUP_PENDING/CONNECTED|Primary/Peer) + # nothing to do, only update pacemaker's view + echo MASTER > $STATE_FILE ++ ++ if [ -n "$remote_host" ]; then ++ for db in $dblist ++ do ++ reint_attr="db2hadr-${inst1}_${inst2}_${db}_reint" ++ ocf_log debug "Promotion succeeded, setting $reint_attr = 1" ++ crm_attribute -n "$reint_attr" -N "$remote_host" -v "1" -l forever ++ done ++ fi ++ + return $OCF_SUCCESS + ;; + +@@ -981,6 +991,15 @@ db2_promote() { + # update pacemaker's view + echo MASTER > $STATE_FILE + ++ if [ -n "$remote_host" ]; then ++ for db in $dblist ++ do ++ reint_attr="db2hadr-${inst1}_${inst2}_${db}_reint" ++ ocf_log debug "Promotion succeeded, setting $reint_attr = 1" ++ crm_attribute -n "$reint_attr" -N "$remote_host" -v "1" -l forever ++ done ++ fi ++ + return $OCF_SUCCESS + fi + diff --git a/SOURCES/RHEL-157190-fix-bundled-pyasn1-CVE-2026-30922.patch b/SOURCES/RHEL-157190-fix-bundled-pyasn1-CVE-2026-30922.patch new file mode 100644 index 0000000..b80a091 --- /dev/null +++ b/SOURCES/RHEL-157190-fix-bundled-pyasn1-CVE-2026-30922.patch @@ -0,0 +1,40 @@ +From 25ad481c19fdb006e20485ef3fc2e5b3eff30ef0 Mon Sep 17 00:00:00 2001 +From: Simon Pichugin +Date: Mon, 16 Mar 2026 17:23:11 -0700 +Subject: [PATCH] Merge commit from fork + +--- + pyasn1/codec/ber/decoder.py | 10 +++ + tests/codec/ber/test_decoder.py | 116 ++++++++++++++++++++++++++++++++ + tests/codec/cer/test_decoder.py | 24 +++++++ + tests/codec/der/test_decoder.py | 42 ++++++++++++ + 4 files changed, 192 insertions(+) + +diff --git a/gcp/google-cloud-sdk/lib/third_party/pyasn1/codec/ber/decoder.py b/gcp/google-cloud-sdk/lib/third_party/pyasn1/codec/ber/decoder.py +index 50b14e98..2ea0be13 100644 +--- a/gcp/google-cloud-sdk/lib/third_party/pyasn1/codec/ber/decoder.py ++++ b/gcp/google-cloud-sdk/lib/third_party/pyasn1/codec/ber/decoder.py +@@ -36,6 +36,7 @@ + # Maximum number of continuation octets (high-bit set) allowed per OID arc. + # 20 octets allows up to 140-bit integers, supporting UUID-based OIDs + MAX_OID_ARC_CONTINUATION_OCTETS = 20 ++MAX_NESTING_DEPTH = 100 + + # Maximum number of bytes in a BER length field (8 bytes = up to 2^64-1) + MAX_LENGTH_OCTETS = 8 +@@ -1568,6 +1569,15 @@ def __call__(self, substrate, asn1Spec=None, + decodeFun=None, substrateFun=None, + **options): + ++ _nestingLevel = options.get('_nestingLevel', 0) ++ ++ if _nestingLevel > MAX_NESTING_DEPTH: ++ raise error.PyAsn1Error( ++ 'ASN.1 structure nesting depth exceeds limit (%d)' % MAX_NESTING_DEPTH ++ ) ++ ++ options['_nestingLevel'] = _nestingLevel + 1 ++ + allowEoo = options.pop('allowEoo', False) + + if LOG: diff --git a/SOURCES/RHEL-16248-aws-vpc-move-ip-aws-vpc-route53-awseip-awsvip-auth_type-role.patch b/SOURCES/RHEL-16248-aws-vpc-move-ip-aws-vpc-route53-awseip-awsvip-auth_type-role.patch new file mode 100644 index 0000000..7d3256d --- /dev/null +++ b/SOURCES/RHEL-16248-aws-vpc-move-ip-aws-vpc-route53-awseip-awsvip-auth_type-role.patch @@ -0,0 +1,555 @@ +From f45f76600a7e02c860566db7d1350dc3b09449c2 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 6 Nov 2023 15:49:44 +0100 +Subject: [PATCH] aws-vpc-move-ip/aws-vpc-route53/awseip/awsvip: add auth_type + parameter and AWS Policy based authentication type + +--- + heartbeat/aws-vpc-move-ip | 43 +++++++++++++++++++---- + heartbeat/aws-vpc-route53.in | 47 ++++++++++++++++++++----- + heartbeat/awseip | 68 +++++++++++++++++++++++++++--------- + heartbeat/awsvip | 60 ++++++++++++++++++++++++------- + 4 files changed, 173 insertions(+), 45 deletions(-) + +diff --git a/heartbeat/aws-vpc-move-ip b/heartbeat/aws-vpc-move-ip +index dee040300f..54806f6eaa 100755 +--- a/heartbeat/aws-vpc-move-ip ++++ b/heartbeat/aws-vpc-move-ip +@@ -36,6 +36,7 @@ + + # Defaults + OCF_RESKEY_awscli_default="/usr/bin/aws" ++OCF_RESKEY_auth_type_default="key" + OCF_RESKEY_profile_default="default" + OCF_RESKEY_region_default="" + OCF_RESKEY_ip_default="" +@@ -48,6 +49,7 @@ OCF_RESKEY_monapi_default="false" + OCF_RESKEY_lookup_type_default="InstanceId" + + : ${OCF_RESKEY_awscli=${OCF_RESKEY_awscli_default}} ++: ${OCF_RESKEY_auth_type=${OCF_RESKEY_auth_type_default}} + : ${OCF_RESKEY_profile=${OCF_RESKEY_profile_default}} + : ${OCF_RESKEY_region=${OCF_RESKEY_region_default}} + : ${OCF_RESKEY_ip=${OCF_RESKEY_ip_default}} +@@ -58,8 +60,6 @@ OCF_RESKEY_lookup_type_default="InstanceId" + : ${OCF_RESKEY_iflabel=${OCF_RESKEY_iflabel_default}} + : ${OCF_RESKEY_monapi=${OCF_RESKEY_monapi_default}} + : ${OCF_RESKEY_lookup_type=${OCF_RESKEY_lookup_type_default}} +- +-[ -n "$OCF_RESKEY_region" ] && region_opt="--region $OCF_RESKEY_region" + ####################################################################### + + +@@ -83,6 +83,10 @@ cat < + Resource Agent to move IP addresses within a VPC of the Amazon Webservices EC2 + by changing an entry in an specific routing table ++ ++Credentials needs to be setup by running "aws configure", or by using AWS Policies. ++ ++See https://aws.amazon.com/cli/ for more information about awscli. + + Move IP within a VPC of the AWS EC2 + +@@ -95,6 +99,15 @@ Path to command line tools for AWS + + + ++ ++ ++Authentication type "key" for AccessKey and SecretAccessKey set via "aws configure", ++or "role" to use AWS Policies. ++ ++Authentication type ++ ++ ++ + + + Valid AWS CLI profile name (see ~/.aws/config and 'aws configure') +@@ -198,7 +211,7 @@ END + 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 $region_opt --output=text)" ++ output="$($AWSCLI_CMD sts assume-role --role-arn $role --role-session-name AWSCLI-RouteTableUpdate --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}')" +@@ -220,11 +233,11 @@ ec2ip_set_address_param_compat(){ + } + + ec2ip_validate() { +- for cmd in $OCF_RESKEY_awscli ip curl; do ++ for cmd in "$OCF_RESKEY_awscli" ip curl; do + check_binary "$cmd" + done + +- if [ -z "$OCF_RESKEY_profile" ]; then ++ if [ "x${OCF_RESKEY_auth_type}" = "xkey" ] && [ -z "$OCF_RESKEY_profile" ]; then + ocf_exit_reason "profile parameter not set" + return $OCF_ERR_CONFIGURED + fi +@@ -262,7 +275,7 @@ ec2ip_monitor() { + 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 $region_opt --output text ec2 describe-route-tables --route-table-ids $rtb --query RouteTables[*].Routes[?DestinationCidrBlock=='$OCF_RESKEY_ip/32'].$OCF_RESKEY_lookup_type" ++ cmd="$AWSCLI_CMD --output text ec2 describe-route-tables --route-table-ids $rtb --query RouteTables[*].Routes[?DestinationCidrBlock=='$OCF_RESKEY_ip/32'].$OCF_RESKEY_lookup_type" + ocf_log debug "executing command: $cmd" + ROUTE_TO_INSTANCE="$($cmd)" + else +@@ -368,7 +381,7 @@ ec2ip_get_and_configure() { + EC2_NETWORK_INTERFACE_ID="$(ec2ip_get_instance_eni)" + 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 $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" ++ cmd="$AWSCLI_CMD --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 +@@ -475,6 +488,22 @@ if ! ocf_is_root; then + exit $OCF_ERR_PERM + fi + ++AWSCLI_CMD="${OCF_RESKEY_awscli}" ++if [ "x${OCF_RESKEY_auth_type}" = "xkey" ]; then ++ AWSCLI_CMD="$AWSCLI_CMD --profile ${OCF_RESKEY_profile}" ++elif [ "x${OCF_RESKEY_auth_type}" = "xrole" ]; then ++ if [ -z "${OCF_RESKEY_region}" ]; then ++ ocf_exit_reason "region needs to be set when using role-based authentication" ++ exit $OCF_ERR_CONFIGURED ++ fi ++else ++ ocf_exit_reason "Incorrect auth_type: ${OCF_RESKEY_auth_type}" ++ exit $OCF_ERR_CONFIGURED ++fi ++if [ -n "${OCF_RESKEY_region}" ]; then ++ AWSCLI_CMD="$AWSCLI_CMD --region ${OCF_RESKEY_region}" ++fi ++ + ec2ip_set_address_param_compat + + ec2ip_validate +diff --git a/heartbeat/aws-vpc-route53.in b/heartbeat/aws-vpc-route53.in +index 22cbb35833..18ab157e8a 100644 +--- a/heartbeat/aws-vpc-route53.in ++++ b/heartbeat/aws-vpc-route53.in +@@ -46,24 +46,22 @@ + + # Defaults + OCF_RESKEY_awscli_default="/usr/bin/aws" ++OCF_RESKEY_auth_type_default="key" + OCF_RESKEY_profile_default="default" ++OCF_RESKEY_region_default="" + OCF_RESKEY_hostedzoneid_default="" + OCF_RESKEY_fullname_default="" + OCF_RESKEY_ip_default="local" + OCF_RESKEY_ttl_default=10 + + : ${OCF_RESKEY_awscli=${OCF_RESKEY_awscli_default}} ++: ${OCF_RESKEY_auth_type=${OCF_RESKEY_auth_type_default}} + : ${OCF_RESKEY_profile=${OCF_RESKEY_profile_default}} ++: ${OCF_RESKEY_region=${OCF_RESKEY_region_default}} + : ${OCF_RESKEY_hostedzoneid:=${OCF_RESKEY_hostedzoneid_default}} + : ${OCF_RESKEY_fullname:=${OCF_RESKEY_fullname_default}} + : ${OCF_RESKEY_ip:=${OCF_RESKEY_ip_default}} + : ${OCF_RESKEY_ttl:=${OCF_RESKEY_ttl_default}} +-####################################################################### +- +- +-AWS_PROFILE_OPT="--profile $OCF_RESKEY_profile --cli-connect-timeout 10" +-####################################################################### +- + + usage() { + cat <<-EOT +@@ -123,6 +121,15 @@ Path to command line tools for AWS + + + ++ ++ ++Authentication type "key" for AccessKey and SecretAccessKey set via "aws configure", ++or "role" to use AWS Policies. ++ ++Authentication type ++ ++ ++ + + + The name of the AWS CLI profile of the root account. This +@@ -196,7 +203,7 @@ r53_validate() { + + # Check for required binaries + ocf_log debug "Checking for required binaries" +- for command in curl dig; do ++ for command in "${OCF_RESKEY_awscli}" curl dig; do + check_binary "$command" + done + +@@ -216,7 +223,10 @@ r53_validate() { + esac + + # profile +- [[ -z "$OCF_RESKEY_profile" ]] && ocf_log error "AWS CLI profile not set $OCF_RESKEY_profile!" && exit $OCF_ERR_CONFIGURED ++ if [ "x${OCF_RESKEY_auth_type}" = "xkey" ] && [ -z "$OCF_RESKEY_profile" ]; then ++ ocf_exit_reason "profile parameter not set" ++ return $OCF_ERR_CONFIGURED ++ fi + + # TTL + [[ -z "$OCF_RESKEY_ttl" ]] && ocf_log error "TTL not set $OCF_RESKEY_ttl!" && exit $OCF_ERR_CONFIGURED +@@ -417,7 +427,6 @@ _update_record() { + } + + ############################################################################### +- + case $__OCF_ACTION in + usage|help) + usage +@@ -427,6 +436,26 @@ case $__OCF_ACTION in + metadata + exit $OCF_SUCCESS + ;; ++esac ++ ++AWSCLI_CMD="${OCF_RESKEY_awscli}" ++if [ "x${OCF_RESKEY_auth_type}" = "xkey" ]; then ++ AWSCLI_CMD="$AWSCLI_CMD --profile ${OCF_RESKEY_profile}" ++elif [ "x${OCF_RESKEY_auth_type}" = "xrole" ]; then ++ if [ -z "${OCF_RESKEY_region}" ]; then ++ ocf_exit_reason "region needs to be set when using role-based authentication" ++ exit $OCF_ERR_CONFIGURED ++ fi ++else ++ ocf_exit_reason "Incorrect auth_type: ${OCF_RESKEY_auth_type}" ++ exit $OCF_ERR_CONFIGURED ++fi ++if [ -n "${OCF_RESKEY_region}" ]; then ++ AWSCLI_CMD="$AWSCLI_CMD --region ${OCF_RESKEY_region}" ++fi ++AWSCLI_CMD="$AWSCLI_CMD --cli-connect-timeout 10" ++ ++case $__OCF_ACTION in + start) + r53_validate || exit $? + r53_start +diff --git a/heartbeat/awseip b/heartbeat/awseip +index dc48460c85..49b0ca6155 100755 +--- a/heartbeat/awseip ++++ b/heartbeat/awseip +@@ -23,7 +23,8 @@ + # + # Prerequisites: + # +-# - preconfigured AWS CLI running environment (AccessKey, SecretAccessKey, etc.) ++# - preconfigured AWS CLI running environment (AccessKey, SecretAccessKey, etc.) or ++# (AWSRole) Setup up relevant AWS Policies to allow agent related functions to be executed. + # - a reserved secondary private IP address for EC2 instances high availability + # - IAM user role with the following permissions: + # * DescribeInstances +@@ -44,11 +45,15 @@ + # Defaults + # + OCF_RESKEY_awscli_default="/usr/bin/aws" ++OCF_RESKEY_auth_type_default="key" + OCF_RESKEY_profile_default="default" ++OCF_RESKEY_region_default="" + OCF_RESKEY_api_delay_default="3" + + : ${OCF_RESKEY_awscli=${OCF_RESKEY_awscli_default}} ++: ${OCF_RESKEY_auth_type=${OCF_RESKEY_auth_type_default}} + : ${OCF_RESKEY_profile=${OCF_RESKEY_profile_default}} ++: ${OCF_RESKEY_region=${OCF_RESKEY_region_default}} + : ${OCF_RESKEY_api_delay=${OCF_RESKEY_api_delay_default}} + + meta_data() { +@@ -63,7 +68,7 @@ Resource Agent for Amazon AWS Elastic IP Addresses. + + It manages AWS Elastic IP Addresses with awscli. + +-Credentials needs to be setup by running "aws configure". ++Credentials needs to be setup by running "aws configure", or by using AWS Policies. + + See https://aws.amazon.com/cli/ for more information about awscli. + +@@ -79,6 +84,15 @@ command line tools for aws services + + + ++ ++ ++Authentication type "key" for AccessKey and SecretAccessKey set via "aws configure", ++or "role" to use AWS Policies. ++ ++Authentication type ++ ++ ++ + + + Valid AWS CLI profile name (see ~/.aws/config and 'aws configure') +@@ -111,6 +125,14 @@ predefined private ip address for ec2 instance + + + ++ ++ ++Region for AWS resource (required for role-based authentication) ++ ++Region ++ ++ ++ + + + a short delay between API calls, to avoid sending API too quick +@@ -157,13 +179,13 @@ awseip_start() { + 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 \ ++ $AWSCLI_CMD ec2 associate-address \ + --network-interface-id ${NETWORK_ID} \ + --allocation-id ${ALLOCATION_ID} \ + --private-ip-address ${PRIVATE_IP_ADDRESS} + RET=$? + else +- $AWSCLI --profile $OCF_RESKEY_profile ec2 associate-address \ ++ $AWSCLI_CMD ec2 associate-address \ + --instance-id ${INSTANCE_ID} \ + --allocation-id ${ALLOCATION_ID} + RET=$? +@@ -183,7 +205,7 @@ awseip_start() { + awseip_stop() { + awseip_monitor || return $OCF_SUCCESS + +- ASSOCIATION_ID=$($AWSCLI --profile $OCF_RESKEY_profile --output json ec2 describe-addresses \ ++ ASSOCIATION_ID=$($AWSCLI_CMD --output json ec2 describe-addresses \ + --allocation-id ${ALLOCATION_ID} | grep -m 1 "AssociationId" | awk -F'"' '{print$4}') + + if [ -z "${ASSOCIATION_ID}" ]; then +@@ -191,9 +213,7 @@ awseip_stop() { + return $OCF_NOT_RUNNING + fi + +- $AWSCLI --profile ${OCF_RESKEY_profile} \ +- ec2 disassociate-address \ +- --association-id ${ASSOCIATION_ID} ++ $AWSCLI_CMD ec2 disassociate-address --association-id ${ASSOCIATION_ID} + RET=$? + + # delay to avoid sending request too fast +@@ -208,7 +228,7 @@ awseip_stop() { + } + + awseip_monitor() { +- $AWSCLI --profile $OCF_RESKEY_profile ec2 describe-instances --instance-id "${INSTANCE_ID}" | grep -q "${ELASTIC_IP}" ++ $AWSCLI_CMD ec2 describe-instances --instance-id "${INSTANCE_ID}" | grep -q "${ELASTIC_IP}" + RET=$? + + if [ $RET -ne 0 ]; then +@@ -218,9 +238,9 @@ awseip_monitor() { + } + + awseip_validate() { +- check_binary ${AWSCLI} ++ check_binary "${OCF_RESKEY_awscli}" + +- if [ -z "$OCF_RESKEY_profile" ]; then ++ if [ "x${OCF_RESKEY_auth_type}" = "xkey" ] && [ -z "$OCF_RESKEY_profile" ]; then + ocf_exit_reason "profile parameter not set" + return $OCF_ERR_CONFIGURED + fi +@@ -238,9 +258,27 @@ case $__OCF_ACTION in + meta_data + exit $OCF_SUCCESS + ;; +-esac ++ usage|help) ++ awseip_usage ++ exit $OCF_SUCCESS ++ ;; ++esac + +-AWSCLI="${OCF_RESKEY_awscli}" ++AWSCLI_CMD="${OCF_RESKEY_awscli}" ++if [ "x${OCF_RESKEY_auth_type}" = "xkey" ]; then ++ AWSCLI_CMD="$AWSCLI_CMD --profile ${OCF_RESKEY_profile}" ++elif [ "x${OCF_RESKEY_auth_type}" = "xrole" ]; then ++ if [ -z "${OCF_RESKEY_region}" ]; then ++ ocf_exit_reason "region needs to be set when using role-based authentication" ++ exit $OCF_ERR_CONFIGURED ++ fi ++else ++ ocf_exit_reason "Incorrect auth_type: ${OCF_RESKEY_auth_type}" ++ exit $OCF_ERR_CONFIGURED ++fi ++if [ -n "${OCF_RESKEY_region}" ]; then ++ AWSCLI_CMD="$AWSCLI_CMD --region ${OCF_RESKEY_region}" ++fi + ELASTIC_IP="${OCF_RESKEY_elastic_ip}" + ALLOCATION_ID="${OCF_RESKEY_allocation_id}" + PRIVATE_IP_ADDRESS="${OCF_RESKEY_private_ip_address}" +@@ -272,10 +310,6 @@ case $__OCF_ACTION in + validate|validate-all) + awseip_validate + ;; +- usage|help) +- awseip_usage +- exit $OCF_SUCCESS +- ;; + *) + awseip_usage + exit $OCF_ERR_UNIMPLEMENTED +diff --git a/heartbeat/awsvip b/heartbeat/awsvip +index 037278e296..bdb4d68dd0 100755 +--- a/heartbeat/awsvip ++++ b/heartbeat/awsvip +@@ -23,7 +23,8 @@ + # + # Prerequisites: + # +-# - preconfigured AWS CLI running environment (AccessKey, SecretAccessKey, etc.) ++# - preconfigured AWS CLI running environment (AccessKey, SecretAccessKey, etc.) or ++# (AWSRole) Setup up relevant AWS Policies to allow agent related functions to be executed. + # - a reserved secondary private IP address for EC2 instances high availablity + # - IAM user role with the following permissions: + # * DescribeInstances +@@ -43,11 +44,15 @@ + # Defaults + # + OCF_RESKEY_awscli_default="/usr/bin/aws" ++OCF_RESKEY_auth_type_default="key" + OCF_RESKEY_profile_default="default" ++OCF_RESKEY_region_default="" + OCF_RESKEY_api_delay_default="3" + + : ${OCF_RESKEY_awscli=${OCF_RESKEY_awscli_default}} ++: ${OCF_RESKEY_auth_type=${OCF_RESKEY_auth_type_default}} + : ${OCF_RESKEY_profile=${OCF_RESKEY_profile_default}} ++: ${OCF_RESKEY_region=${OCF_RESKEY_region_default}} + : ${OCF_RESKEY_api_delay=${OCF_RESKEY_api_delay_default}} + + meta_data() { +@@ -62,7 +67,7 @@ Resource Agent for Amazon AWS Secondary Private IP Addresses. + + It manages AWS Secondary Private IP Addresses with awscli. + +-Credentials needs to be setup by running "aws configure". ++Credentials needs to be setup by running "aws configure", or by using AWS Policies. + + See https://aws.amazon.com/cli/ for more information about awscli. + +@@ -78,6 +83,15 @@ command line tools for aws services + + + ++ ++ ++Authentication type "key" for AccessKey and SecretAccessKey set via "aws configure", ++or "role" to use AWS Policies. ++ ++Authentication type ++ ++ ++ + + + Valid AWS CLI profile name (see ~/.aws/config and 'aws configure') +@@ -94,6 +108,14 @@ reserved secondary private ip for ec2 instance + + + ++ ++ ++Region for AWS resource (required for role-based authentication) ++ ++Region ++ ++ ++ + + + a short delay between API calls, to avoid sending API too quick +@@ -131,7 +153,7 @@ END + awsvip_start() { + awsvip_monitor && return $OCF_SUCCESS + +- $AWSCLI --profile $OCF_RESKEY_profile ec2 assign-private-ip-addresses \ ++ $AWSCLI_CMD ec2 assign-private-ip-addresses \ + --network-interface-id ${NETWORK_ID} \ + --private-ip-addresses ${SECONDARY_PRIVATE_IP} \ + --allow-reassignment +@@ -151,7 +173,7 @@ awsvip_start() { + awsvip_stop() { + awsvip_monitor || return $OCF_SUCCESS + +- $AWSCLI --profile $OCF_RESKEY_profile ec2 unassign-private-ip-addresses \ ++ $AWSCLI_CMD ec2 unassign-private-ip-addresses \ + --network-interface-id ${NETWORK_ID} \ + --private-ip-addresses ${SECONDARY_PRIVATE_IP} + RET=$? +@@ -168,7 +190,7 @@ awsvip_stop() { + } + + awsvip_monitor() { +- $AWSCLI --profile ${OCF_RESKEY_profile} ec2 describe-instances \ ++ $AWSCLI_CMD ec2 describe-instances \ + --instance-id "${INSTANCE_ID}" \ + --query 'Reservations[].Instances[].NetworkInterfaces[].PrivateIpAddresses[].PrivateIpAddress[]' \ + --output text | \ +@@ -182,9 +204,9 @@ awsvip_monitor() { + } + + awsvip_validate() { +- check_binary ${AWSCLI} ++ check_binary "${OCF_RESKEY_awscli}" + +- if [ -z "$OCF_RESKEY_profile" ]; then ++ if [ "x${OCF_RESKEY_auth_type}" = "xkey" ] && [ -z "$OCF_RESKEY_profile" ]; then + ocf_exit_reason "profile parameter not set" + return $OCF_ERR_CONFIGURED + fi +@@ -202,9 +224,27 @@ case $__OCF_ACTION in + meta_data + exit $OCF_SUCCESS + ;; ++ usage|help) ++ awsvip_usage ++ exit $OCF_SUCCESS ++ ;; + esac + +-AWSCLI="${OCF_RESKEY_awscli}" ++AWSCLI_CMD="${OCF_RESKEY_awscli}" ++if [ "x${OCF_RESKEY_auth_type}" = "xkey" ]; then ++ AWSCLI_CMD="$AWSCLI_CMD --profile ${OCF_RESKEY_profile}" ++elif [ "x${OCF_RESKEY_auth_type}" = "xrole" ]; then ++ if [ -z "${OCF_RESKEY_region}" ]; then ++ ocf_exit_reason "region needs to be set when using role-based authentication" ++ exit $OCF_ERR_CONFIGURED ++ fi ++else ++ ocf_exit_reason "Incorrect auth_type: ${OCF_RESKEY_auth_type}" ++ exit $OCF_ERR_CONFIGURED ++fi ++if [ -n "${OCF_RESKEY_region}" ]; then ++ AWSCLI_CMD="$AWSCLI_CMD --region ${OCF_RESKEY_region}" ++fi + SECONDARY_PRIVATE_IP="${OCF_RESKEY_secondary_private_ip}" + TOKEN=$(curl -sX 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") +@@ -236,10 +276,6 @@ case $__OCF_ACTION in + validate|validate-all) + awsvip_validate + ;; +- usage|help) +- awsvip_usage +- exit $OCF_SUCCESS +- ;; + *) + awsvip_usage + exit $OCF_ERR_UNIMPLEMENTED diff --git a/SOURCES/RHEL-166181-1-db2-fix-bashism.patch b/SOURCES/RHEL-166181-1-db2-fix-bashism.patch new file mode 100644 index 0000000..e2167a2 --- /dev/null +++ b/SOURCES/RHEL-166181-1-db2-fix-bashism.patch @@ -0,0 +1,32 @@ +From 3712b1f52bccddc767ad6f16ec67d6c8c29f1f71 Mon Sep 17 00:00:00 2001 +From: Valentin Vidic +Date: Sun, 3 Apr 2022 20:39:01 +0200 +Subject: [PATCH] db2: fix bashism + +dash only allows -a as AND operator. +--- + heartbeat/db2 | 4 ++-- + 1 file changed, 2 insertions(+), 2 deletions(-) + +diff --git a/heartbeat/db2 b/heartbeat/db2 +index ea24d33fc8..4a4b2f477f 100755 +--- a/heartbeat/db2 ++++ b/heartbeat/db2 +@@ -407,7 +407,7 @@ db2_start() { + # partition is explicitly specified, activate without + # partition information. This allows db2 instances without + # partition support to be managed. +- if [ -z "$OCF_RESKEY_dbpartitionnum" ] && ! [ -a "$db2sql/db2nodes.cfg" ]; then ++ if [ -z "$OCF_RESKEY_dbpartitionnum" ] && ! [ -e "$db2sql/db2nodes.cfg" ]; then + start_opts="" + fi + +@@ -511,7 +511,7 @@ db2_stop_bg() { + + rc=$OCF_SUCCESS + +- if [ -z "$OCF_RESKEY_dbpartitionnum" ] && ! [ -a "$db2sql/db2nodes.cfg" ]; then ++ if [ -z "$OCF_RESKEY_dbpartitionnum" ] && ! [ -e "$db2sql/db2nodes.cfg" ]; then + stop_opts="" + fi + diff --git a/SOURCES/RHEL-166181-2-db2-do-not-use-db2stop-to-avoid-divergence-in-the-log.patch b/SOURCES/RHEL-166181-2-db2-do-not-use-db2stop-to-avoid-divergence-in-the-log.patch new file mode 100644 index 0000000..0b0e0fa --- /dev/null +++ b/SOURCES/RHEL-166181-2-db2-do-not-use-db2stop-to-avoid-divergence-in-the-log.patch @@ -0,0 +1,143 @@ +From 26c0d48bc69da1859f1ce5205a8bb6eaf6297b81 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Wed, 25 Mar 2026 10:46:09 +0100 +Subject: [PATCH] db2: do not use db2stop, as it sends truncation messages, + which in some cases are not delivered + +This caused divergence in the log, and the user would have to manually rebuild +the DB to recover from it. +--- + heartbeat/db2 | 104 +++++++------------------------------------------- + 1 file changed, 13 insertions(+), 91 deletions(-) + +diff --git a/heartbeat/db2 b/heartbeat/db2 +index 4420b9989..9de18639d 100755 +--- a/heartbeat/db2 ++++ b/heartbeat/db2 +@@ -596,45 +596,10 @@ db2_start() { + return $OCF_SUCCESS + } + +-# +-# helper function to be spawned +-# so we can detect a hang of the db2stop command +-# +-db2_stop_bg() { +- local rc output +- local stop_opts="dbpartitionnum $db2node" +- +- rc=$OCF_SUCCESS +- +- if [ -z "$OCF_RESKEY_dbpartitionnum" ] && ! [ -e "$db2sql/db2nodes.cfg" ]; then +- stop_opts="" +- fi +- +- if output=$(runasdb2 db2stop force $stop_opts) +- then +- ocf_log info "DB2 instance $instance($db2node) stopped: $output" +- else +- case $output in +- *SQL1032N*) +- #SQL1032N No start database manager command was issued +- ocf_log info "$output" +- ;; +- +- *) +- ocf_log err "DB2 instance $instance($db2node) stop failed: $output" +- rc=$OCF_ERR_GENERIC +- esac +- fi +- +- return $rc +-} +- + # + # Stop the given db2 database instance + # + db2_stop() { +- local stop_timeout grace_timeout stop_bg_pid i must_kill +- + # remove master score + master_score -D -l reboot + +@@ -647,67 +612,24 @@ db2_stop() { + return $OCF_SUCCESS + fi + +- stop_timeout=${OCF_RESKEY_CRM_meta_timeout:-20000} +- +- # grace_time is 4/5 (unit is ms) +- grace_timeout=$((stop_timeout/1250)) +- +- # start db2stop in background as this may hang +- db2_stop_bg & +- stop_bg_pid=$! +- +- # wait for grace_timeout +- i=0 +- while [ $i -lt $grace_timeout ] +- do +- kill -0 $stop_bg_pid 2>/dev/null || break; +- sleep 1 +- i=$((i+1)) +- done +- +- # collect exit status but don't hang +- if kill -0 $stop_bg_pid 2>/dev/null +- then +- stoprc=1 +- kill -9 $stop_bg_pid 2>/dev/null +- else +- wait $stop_bg_pid +- stoprc=$? +- fi +- +- must_kill=0 +- +- if [ $stoprc -ne 0 ] ++ # db2nkill kills *all* partitions on the node ++ if [ -x $db2bin/db2nkill ] + then +- ocf_log warn "DB2 instance $instance($db2node): db2stop failed, using db2nkill" +- must_kill=1 +- elif ! db2_instance_dead ++ logasdb2 $db2bin/db2nkill $db2node ++ elif [ -x $db2bin/db2_kill ] + then +- ocf_log warn "DB2 instance $instance($db2node): db2stop indicated success but there a still processes, using db2nkill" +- must_kill=1 ++ logasdb2 $db2bin/db2_kill + fi + +- if [ $must_kill -eq 1 ] +- then +- # db2nkill kills *all* partitions on the node +- if [ -x $db2bin/db2nkill ] +- then +- logasdb2 $db2bin/db2nkill $db2node +- elif [ -x $db2bin/db2_kill ] +- then +- logasdb2 $db2bin/db2_kill +- fi +- +- # loop forever (or lrmd kills us due to timeout) until the +- # instance is dead +- while ! db2_instance_dead +- do +- ocf_log info "DB2 instance $instance($db2node): waiting for processes to exit" +- sleep 1 +- done ++ # loop forever (or lrmd kills us due to timeout) until the ++ # instance is dead ++ while ! db2_instance_dead ++ do ++ ocf_log info "DB2 instance $instance($db2node): waiting for processes to exit" ++ sleep 1 ++ done + +- ocf_log info "DB2 instance $instance($db2node) is now dead" +- fi ++ ocf_log info "DB2 instance $instance($db2node) is now dead" + + return $OCF_SUCCESS + } diff --git a/SOURCES/RHEL-17083-findif-EOS-fix.patch b/SOURCES/RHEL-17083-findif-EOS-fix.patch new file mode 100644 index 0000000..aaf5505 --- /dev/null +++ b/SOURCES/RHEL-17083-findif-EOS-fix.patch @@ -0,0 +1,22 @@ +From b23ba4eaefb500199c4845751f4c5545c81f42f1 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 20 Nov 2023 16:37:37 +0100 +Subject: [PATCH 2/2] findif: also check that netmaskbits != EOS + +--- + tools/findif.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/tools/findif.c b/tools/findif.c +index a25395fec..ab108a3c4 100644 +--- a/tools/findif.c ++++ b/tools/findif.c +@@ -669,7 +669,7 @@ main(int argc, char ** argv) { + } + } + +- if (netmaskbits) { ++ if (netmaskbits != NULL && *netmaskbits != EOS) { + best_netmask = netmask; + }else if (best_netmask == 0L) { + /* diff --git a/SOURCES/RHEL-32828-db2-fix-OCF_SUCESS-typo.patch b/SOURCES/RHEL-32828-db2-fix-OCF_SUCESS-typo.patch new file mode 100644 index 0000000..bbe2847 --- /dev/null +++ b/SOURCES/RHEL-32828-db2-fix-OCF_SUCESS-typo.patch @@ -0,0 +1,23 @@ +From a9c4aeb971e9f4963345d0e215b729def62dd27c Mon Sep 17 00:00:00 2001 +From: pepadelic <162310096+pepadelic@users.noreply.github.com> +Date: Mon, 15 Apr 2024 13:52:54 +0200 +Subject: [PATCH] Update db2: fix OCF_SUCESS name in db2_notify + +fix OCF_SUCESS to OCF_SUCCESS in db2_notify +--- + heartbeat/db2 | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/db2 b/heartbeat/db2 +index 95447ab6cb..1cd66f15af 100755 +--- a/heartbeat/db2 ++++ b/heartbeat/db2 +@@ -848,7 +848,7 @@ db2_notify() { + + # only interested in pre-start + [ $OCF_RESKEY_CRM_meta_notify_type = pre \ +- -a $OCF_RESKEY_CRM_meta_notify_operation = start ] || return $OCF_SUCESS ++ -a $OCF_RESKEY_CRM_meta_notify_operation = start ] || return $OCF_SUCCESS + + # gets FIRST_ACTIVE_LOG + db2_get_cfg $dblist || return $? diff --git a/SOURCES/RHEL-34137-aws-agents-use-curl_retry.patch b/SOURCES/RHEL-34137-aws-agents-use-curl_retry.patch new file mode 100644 index 0000000..9f035a7 --- /dev/null +++ b/SOURCES/RHEL-34137-aws-agents-use-curl_retry.patch @@ -0,0 +1,343 @@ +From fc0657b936f6a58f741e33f851b22f82bc68bffa Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 6 Feb 2024 13:28:12 +0100 +Subject: [PATCH 1/2] ocf-shellfuncs: add curl_retry() + +--- + heartbeat/ocf-shellfuncs.in | 34 ++++++++++++++++++++++++++++++++++ + 1 file changed, 34 insertions(+) + +diff --git a/heartbeat/ocf-shellfuncs.in b/heartbeat/ocf-shellfuncs.in +index c5edb6f57..a69a9743d 100644 +--- a/heartbeat/ocf-shellfuncs.in ++++ b/heartbeat/ocf-shellfuncs.in +@@ -672,6 +672,40 @@ EOF + systemctl daemon-reload + } + ++# usage: curl_retry RETRIES SLEEP ARGS URL ++# ++# Use --show-error in ARGS to log HTTP error code ++# ++# returns: ++# 0 success ++# exit: ++# 1 fail ++curl_retry() ++{ ++ local retries=$1 sleep=$2 opts=$3 url=$4 ++ local tries=$(($retries + 1)) ++ local args="--fail $opts $url" ++ local result rc ++ ++ for try in $(seq $tries); do ++ ocf_log debug "curl $args try $try of $tries" ++ result=$(echo "$args" | xargs curl 2>&1) ++ rc=$? ++ ++ ocf_log debug "result: $result" ++ [ $rc -eq 0 ] && break ++ sleep $sleep ++ done ++ ++ if [ $rc -ne 0 ]; then ++ ocf_exit_reason "curl $args failed $tries tries" ++ exit $OCF_ERR_GENERIC ++ fi ++ ++ echo "$result" ++ return $rc ++} ++ + # usage: crm_mon_no_validation args... + # run crm_mon without any cib schema validation + # This is useful when an agent runs in a bundle to avoid potential + +From 80d330557319bdae9e45aad1279e435fc481d4e7 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Tue, 6 Feb 2024 13:28:25 +0100 +Subject: [PATCH 2/2] AWS agents: use curl_retry() + +--- + heartbeat/aws-vpc-move-ip | 35 ++++++++++++++++++++++++++--------- + heartbeat/aws-vpc-route53.in | 27 +++++++++++++++++++++++++-- + heartbeat/awseip | 36 +++++++++++++++++++++++++++++++----- + heartbeat/awsvip | 32 ++++++++++++++++++++++++++++---- + 4 files changed, 110 insertions(+), 20 deletions(-) + +diff --git a/heartbeat/aws-vpc-move-ip b/heartbeat/aws-vpc-move-ip +index 54806f6ea..6115e5ba8 100755 +--- a/heartbeat/aws-vpc-move-ip ++++ b/heartbeat/aws-vpc-move-ip +@@ -47,6 +47,8 @@ OCF_RESKEY_interface_default="eth0" + OCF_RESKEY_iflabel_default="" + OCF_RESKEY_monapi_default="false" + OCF_RESKEY_lookup_type_default="InstanceId" ++OCF_RESKEY_curl_retries_default="3" ++OCF_RESKEY_curl_sleep_default="1" + + : ${OCF_RESKEY_awscli=${OCF_RESKEY_awscli_default}} + : ${OCF_RESKEY_auth_type=${OCF_RESKEY_auth_type_default}} +@@ -60,6 +62,8 @@ OCF_RESKEY_lookup_type_default="InstanceId" + : ${OCF_RESKEY_iflabel=${OCF_RESKEY_iflabel_default}} + : ${OCF_RESKEY_monapi=${OCF_RESKEY_monapi_default}} + : ${OCF_RESKEY_lookup_type=${OCF_RESKEY_lookup_type_default}} ++: ${OCF_RESKEY_curl_retries=${OCF_RESKEY_curl_retries_default}} ++: ${OCF_RESKEY_curl_sleep=${OCF_RESKEY_curl_sleep_default}} + ####################################################################### + + +@@ -194,6 +198,22 @@ Name of resource type to lookup in route table. + + + ++ ++ ++curl retries before failing ++ ++curl retries ++ ++ ++ ++ ++ ++curl sleep between tries ++ ++curl sleep ++ ++ ++ + + + +@@ -250,8 +270,10 @@ ec2ip_validate() { + fi + fi + +- TOKEN=$(curl -sX 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") ++ TOKEN=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "--show-error -sX PUT -H 'X-aws-ec2-metadata-token-ttl-seconds: 21600'" "http://169.254.169.254/latest/api/token") ++ [ $? -ne 0 ] && exit $OCF_ERR_GENERIC ++ EC2_INSTANCE_ID=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "--show-error -s -H 'X-aws-ec2-metadata-token: $TOKEN'" "http://169.254.169.254/latest/meta-data/instance-id") ++ [ $? -ne 0 ] && exit $OCF_ERR_GENERIC + + if [ -z "${EC2_INSTANCE_ID}" ]; then + ocf_exit_reason "Instance ID not found. Is this a EC2 instance?" +@@ -365,14 +387,9 @@ 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 -H \"X-aws-ec2-metadata-token: $TOKEN\"" +- ocf_log debug "executing command: $cmd" ++ cmd="curl_retry \"$OCF_RESKEY_curl_retries\" \"$OCF_RESKEY_curl_sleep\" \"--show-error -s -H 'X-aws-ec2-metadata-token: $TOKEN'\" \"http://169.254.169.254/latest/meta-data/network/interfaces/macs/${MAC_ADDR}/interface-id\"" + EC2_NETWORK_INTERFACE_ID="$(eval $cmd)" +- rc=$? +- if [ $rc != 0 ]; then +- ocf_log warn "command failed, rc: $rc" +- return $OCF_ERR_GENERIC +- fi ++ [ $? -ne 0 ] && exit $OCF_ERR_GENERIC + ocf_log debug "network interface id associated MAC address ${MAC_ADDR}: ${EC2_NETWORK_INTERFACE_ID}" + echo $EC2_NETWORK_INTERFACE_ID + } +diff --git a/heartbeat/aws-vpc-route53.in b/heartbeat/aws-vpc-route53.in +index 18ab157e8..eba2ed95c 100644 +--- a/heartbeat/aws-vpc-route53.in ++++ b/heartbeat/aws-vpc-route53.in +@@ -53,6 +53,8 @@ OCF_RESKEY_hostedzoneid_default="" + OCF_RESKEY_fullname_default="" + OCF_RESKEY_ip_default="local" + OCF_RESKEY_ttl_default=10 ++OCF_RESKEY_curl_retries_default="3" ++OCF_RESKEY_curl_sleep_default="1" + + : ${OCF_RESKEY_awscli=${OCF_RESKEY_awscli_default}} + : ${OCF_RESKEY_auth_type=${OCF_RESKEY_auth_type_default}} +@@ -62,6 +64,8 @@ OCF_RESKEY_ttl_default=10 + : ${OCF_RESKEY_fullname:=${OCF_RESKEY_fullname_default}} + : ${OCF_RESKEY_ip:=${OCF_RESKEY_ip_default}} + : ${OCF_RESKEY_ttl:=${OCF_RESKEY_ttl_default}} ++: ${OCF_RESKEY_curl_retries=${OCF_RESKEY_curl_retries_default}} ++: ${OCF_RESKEY_curl_sleep=${OCF_RESKEY_curl_sleep_default}} + + usage() { + cat <<-EOT +@@ -185,6 +189,22 @@ Time to live for Route53 ARECORD + ARECORD TTL + + ++ ++ ++ ++curl retries before failing ++ ++curl retries ++ ++ ++ ++ ++ ++curl sleep between tries ++ ++curl sleep ++ ++ + + + +@@ -357,8 +377,11 @@ r53_monitor() { + _get_ip() { + case $OCF_RESKEY_ip in + local|public) +- TOKEN=$(curl -sX 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");; ++ TOKEN=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "--show-error -sX PUT -H 'X-aws-ec2-metadata-token-ttl-seconds: 21600'" "http://169.254.169.254/latest/api/token") ++ [ $? -ne 0 ] && exit $OCF_ERR_GENERIC ++ IPADDRESS=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "--show-error -s -H 'X-aws-ec2-metadata-token: $TOKEN'" "http://169.254.169.254/latest/meta-data/${OCF_RESKEY_ip}-ipv4") ++ [ $? -ne 0 ] && exit $OCF_ERR_GENERIC ++ ;; + *.*.*.*) + IPADDRESS="${OCF_RESKEY_ip}";; + esac +diff --git a/heartbeat/awseip b/heartbeat/awseip +index 49b0ca615..ffb6223a1 100755 +--- a/heartbeat/awseip ++++ b/heartbeat/awseip +@@ -49,12 +49,16 @@ OCF_RESKEY_auth_type_default="key" + OCF_RESKEY_profile_default="default" + OCF_RESKEY_region_default="" + OCF_RESKEY_api_delay_default="3" ++OCF_RESKEY_curl_retries_default="3" ++OCF_RESKEY_curl_sleep_default="1" + + : ${OCF_RESKEY_awscli=${OCF_RESKEY_awscli_default}} + : ${OCF_RESKEY_auth_type=${OCF_RESKEY_auth_type_default}} + : ${OCF_RESKEY_profile=${OCF_RESKEY_profile_default}} + : ${OCF_RESKEY_region=${OCF_RESKEY_region_default}} + : ${OCF_RESKEY_api_delay=${OCF_RESKEY_api_delay_default}} ++: ${OCF_RESKEY_curl_retries=${OCF_RESKEY_curl_retries_default}} ++: ${OCF_RESKEY_curl_sleep=${OCF_RESKEY_curl_sleep_default}} + + meta_data() { + cat < + + ++ ++ ++curl retries before failing ++ ++curl retries ++ ++ ++ ++ ++ ++curl sleep between tries ++ ++curl sleep ++ ++ ++ + + + +@@ -171,14 +191,18 @@ 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/ -H "X-aws-ec2-metadata-token: $TOKEN") ++ NETWORK_INTERFACES_MACS=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "-s -H 'X-aws-ec2-metadata-token: $TOKEN'" "http://169.254.169.254/latest/meta-data/network/interfaces/macs/") + for MAC in ${NETWORK_INTERFACES_MACS}; do +- curl -s http://169.254.169.254/latest/meta-data/network/interfaces/macs/${MAC}/local-ipv4s -H "X-aws-ec2-metadata-token: $TOKEN" | ++ curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "-s -H 'X-aws-ec2-metadata-token: $TOKEN'" "http://169.254.169.254/latest/meta-data/network/interfaces/macs/${MAC%/*}/local-ipv4s" | + 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 -H "X-aws-ec2-metadata-token: $TOKEN") ++ NETWORK_ID=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "-s -H 'X-aws-ec2-metadata-token: $TOKEN'" "http://169.254.169.254/latest/meta-data/network/interfaces/macs/${MAC%/*}/interface-id") + fi + done ++ if [ -z "$NETWORK_ID" ]; then ++ ocf_exit_reason "Could not find network interface for private_ip_address: $PRIVATE_IP_ADDRESS" ++ exit $OCF_ERR_GENERIC ++ fi + $AWSCLI_CMD ec2 associate-address \ + --network-interface-id ${NETWORK_ID} \ + --allocation-id ${ALLOCATION_ID} \ +@@ -282,8 +306,10 @@ fi + ELASTIC_IP="${OCF_RESKEY_elastic_ip}" + ALLOCATION_ID="${OCF_RESKEY_allocation_id}" + PRIVATE_IP_ADDRESS="${OCF_RESKEY_private_ip_address}" +-TOKEN=$(curl -sX 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") ++TOKEN=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "--show-error -sX PUT -H 'X-aws-ec2-metadata-token-ttl-seconds: 21600'" "http://169.254.169.254/latest/api/token") ++[ $? -ne 0 ] && exit $OCF_ERR_GENERIC ++INSTANCE_ID=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "--show-error -s -H 'X-aws-ec2-metadata-token: $TOKEN'" "http://169.254.169.254/latest/meta-data/instance-id") ++[ $? -ne 0 ] && exit $OCF_ERR_GENERIC + + case $__OCF_ACTION in + start) +diff --git a/heartbeat/awsvip b/heartbeat/awsvip +index bdb4d68dd..f2b238a0f 100755 +--- a/heartbeat/awsvip ++++ b/heartbeat/awsvip +@@ -48,12 +48,16 @@ OCF_RESKEY_auth_type_default="key" + OCF_RESKEY_profile_default="default" + OCF_RESKEY_region_default="" + OCF_RESKEY_api_delay_default="3" ++OCF_RESKEY_curl_retries_default="3" ++OCF_RESKEY_curl_sleep_default="1" + + : ${OCF_RESKEY_awscli=${OCF_RESKEY_awscli_default}} + : ${OCF_RESKEY_auth_type=${OCF_RESKEY_auth_type_default}} + : ${OCF_RESKEY_profile=${OCF_RESKEY_profile_default}} + : ${OCF_RESKEY_region=${OCF_RESKEY_region_default}} + : ${OCF_RESKEY_api_delay=${OCF_RESKEY_api_delay_default}} ++: ${OCF_RESKEY_curl_retries=${OCF_RESKEY_curl_retries_default}} ++: ${OCF_RESKEY_curl_sleep=${OCF_RESKEY_curl_sleep_default}} + + meta_data() { + cat < + + ++ ++ ++curl retries before failing ++ ++curl retries ++ ++ ++ ++ ++ ++curl sleep between tries ++ ++curl sleep ++ ++ ++ + + + +@@ -246,10 +266,14 @@ if [ -n "${OCF_RESKEY_region}" ]; then + AWSCLI_CMD="$AWSCLI_CMD --region ${OCF_RESKEY_region}" + fi + SECONDARY_PRIVATE_IP="${OCF_RESKEY_secondary_private_ip}" +-TOKEN=$(curl -sX 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") ++TOKEN=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "--show-error -sX PUT -H 'X-aws-ec2-metadata-token-ttl-seconds: 21600'" "http://169.254.169.254/latest/api/token") ++[ $? -ne 0 ] && exit $OCF_ERR_GENERIC ++INSTANCE_ID=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "--show-error -s -H 'X-aws-ec2-metadata-token: $TOKEN'" "http://169.254.169.254/latest/meta-data/instance-id") ++[ $? -ne 0 ] && exit $OCF_ERR_GENERIC ++MAC_ADDRESS=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "--show-error -s -H 'X-aws-ec2-metadata-token: $TOKEN'" "http://169.254.169.254/latest/meta-data/mac") ++[ $? -ne 0 ] && exit $OCF_ERR_GENERIC ++NETWORK_ID=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "--show-error -s -H 'X-aws-ec2-metadata-token: $TOKEN'" "http://169.254.169.254/latest/meta-data/network/interfaces/macs/${MAC_ADDRESS}/interface-id") ++[ $? -ne 0 ] && exit $OCF_ERR_GENERIC + + case $__OCF_ACTION in + start) diff --git a/SOURCES/RHEL-44923-aliyun-gcp-fix-bundled-urllib3-CVE-2024-37891.patch b/SOURCES/RHEL-44923-aliyun-gcp-fix-bundled-urllib3-CVE-2024-37891.patch new file mode 100644 index 0000000..4d0ac31 --- /dev/null +++ b/SOURCES/RHEL-44923-aliyun-gcp-fix-bundled-urllib3-CVE-2024-37891.patch @@ -0,0 +1,48 @@ +From accff72ecc2f6cf5a76d9570198a93ac7c90270e Mon Sep 17 00:00:00 2001 +From: Quentin Pradet +Date: Mon, 17 Jun 2024 11:09:06 +0400 +Subject: [PATCH] Merge pull request from GHSA-34jh-p97f-mpxf + +* Strip Proxy-Authorization header on redirects + +* Fix test_retry_default_remove_headers_on_redirect + +* Set release date +--- + CHANGES.rst | 5 +++++ + src/urllib3/util/retry.py | 4 +++- + test/test_retry.py | 6 ++++- + test/with_dummyserver/test_poolmanager.py | 27 ++++++++++++++++++++--- + 4 files changed, 37 insertions(+), 5 deletions(-) + +diff --git a/aliyun/aliyunsdkcore/vendored/requests/packages/urllib3/util/retry.py b/aliyun/aliyunsdkcore/vendored/requests/packages/urllib3/util/retry.py +index 7a76a4a6ad..0456cceba4 100644 +--- a/aliyun/aliyunsdkcore/vendored/requests/packages/urllib3/util/retry.py ++++ b/aliyun/aliyunsdkcore/vendored/requests/packages/urllib3/util/retry.py +@@ -189,7 +189,9 @@ class Retry: + RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503]) + + #: Default headers to be used for ``remove_headers_on_redirect`` +- DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(["Cookie", "Authorization"]) ++ DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset( ++ ["Cookie", "Authorization", "Proxy-Authorization"] ++ ) + + #: Default maximum backoff time. + DEFAULT_BACKOFF_MAX = 120 + +diff --git a/gcp/google-cloud-sdk/lib/third_party/urllib3/util/retry.py b/gcp/google-cloud-sdk/lib/third_party/urllib3/util/retry.py +index 7a76a4a6ad..0456cceba4 100644 +--- a/gcp/google-cloud-sdk/lib/third_party/urllib3/util/retry.py ++++ b/gcp/google-cloud-sdk/lib/third_party/urllib3/util/retry.py +@@ -189,7 +189,9 @@ class Retry: + RETRY_AFTER_STATUS_CODES = frozenset([413, 429, 503]) + + #: Default headers to be used for ``remove_headers_on_redirect`` +- DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset(["Cookie", "Authorization"]) ++ DEFAULT_REMOVE_HEADERS_ON_REDIRECT = frozenset( ++ ["Cookie", "Authorization", "Proxy-Authorization"] ++ ) + + #: Default maximum backoff time. + DEFAULT_BACKOFF_MAX = 120 diff --git a/SOURCES/RHEL-50360-setuptools-fix-CVE-2024-6345.patch b/SOURCES/RHEL-50360-setuptools-fix-CVE-2024-6345.patch new file mode 100644 index 0000000..423d4cb --- /dev/null +++ b/SOURCES/RHEL-50360-setuptools-fix-CVE-2024-6345.patch @@ -0,0 +1,201 @@ +--- a/setuptools/package_index.py 1980-01-01 09:00:00.000000000 +0100 ++++ b/setuptools/package_index.py 2024-07-25 10:11:40.537307665 +0200 +@@ -1,5 +1,6 @@ + """PyPI and direct package downloading""" + import sys ++import subprocess + import os + import re + import shutil +@@ -563,7 +564,7 @@ + scheme = URL_SCHEME(spec) + if scheme: + # It's a url, download it to tmpdir +- found = self._download_url(scheme.group(1), spec, tmpdir) ++ found = self._download_url(spec, tmpdir) + base, fragment = egg_info_for_url(spec) + if base.endswith('.py'): + found = self.gen_setup(found, fragment, tmpdir) +@@ -775,7 +776,7 @@ + raise DistutilsError("Download error for %s: %s" + % (url, v)) + +- def _download_url(self, scheme, url, tmpdir): ++ def _download_url(self, url, tmpdir): + # Determine download filename + # + name, fragment = egg_info_for_url(url) +@@ -790,19 +791,59 @@ + + filename = os.path.join(tmpdir, name) + +- # Download the file +- # +- if scheme == 'svn' or scheme.startswith('svn+'): +- return self._download_svn(url, filename) +- elif scheme == 'git' or scheme.startswith('git+'): +- return self._download_git(url, filename) +- elif scheme.startswith('hg+'): +- return self._download_hg(url, filename) +- elif scheme == 'file': +- return urllib.request.url2pathname(urllib.parse.urlparse(url)[2]) +- else: +- self.url_ok(url, True) # raises error if not allowed +- return self._attempt_download(url, filename) ++ return self._download_vcs(url, filename) or self._download_other(url, filename) ++ ++ @staticmethod ++ def _resolve_vcs(url): ++ """ ++ >>> rvcs = PackageIndex._resolve_vcs ++ >>> rvcs('git+http://foo/bar') ++ 'git' ++ >>> rvcs('hg+https://foo/bar') ++ 'hg' ++ >>> rvcs('git:myhost') ++ 'git' ++ >>> rvcs('hg:myhost') ++ >>> rvcs('http://foo/bar') ++ """ ++ scheme = urllib.parse.urlsplit(url).scheme ++ pre, sep, post = scheme.partition('+') ++ # svn and git have their own protocol; hg does not ++ allowed = set(['svn', 'git'] + ['hg'] * bool(sep)) ++ return next(iter({pre} & allowed), None) ++ ++ def _download_vcs(self, url, spec_filename): ++ vcs = self._resolve_vcs(url) ++ if not vcs: ++ return ++ if vcs == 'svn': ++ raise DistutilsError( ++ f"Invalid config, SVN download is not supported: {url}" ++ ) ++ ++ filename, _, _ = spec_filename.partition('#') ++ url, rev = self._vcs_split_rev_from_url(url) ++ ++ self.info(f"Doing {vcs} clone from {url} to {filename}") ++ subprocess.check_call([vcs, 'clone', '--quiet', url, filename]) ++ ++ co_commands = dict( ++ git=[vcs, '-C', filename, 'checkout', '--quiet', rev], ++ hg=[vcs, '--cwd', filename, 'up', '-C', '-r', rev, '-q'], ++ ) ++ if rev is not None: ++ self.info(f"Checking out {rev}") ++ subprocess.check_call(co_commands[vcs]) ++ ++ return filename ++ ++ def _download_other(self, url, filename): ++ scheme = urllib.parse.urlsplit(url).scheme ++ if scheme == 'file': # pragma: no cover ++ return urllib.request.url2pathname(urllib.parse.urlparse(url).path) ++ # raise error if not allowed ++ self.url_ok(url, True) ++ return self._attempt_download(url, filename) + + def scan_url(self, url): + self.process_url(url, True) +@@ -829,76 +870,37 @@ + os.unlink(filename) + raise DistutilsError("Unexpected HTML page found at " + url) + +- def _download_svn(self, url, filename): +- url = url.split('#', 1)[0] # remove any fragment for svn's sake +- creds = '' +- if url.lower().startswith('svn:') and '@' in url: +- scheme, netloc, path, p, q, f = urllib.parse.urlparse(url) +- if not netloc and path.startswith('//') and '/' in path[2:]: +- netloc, path = path[2:].split('/', 1) +- auth, host = splituser(netloc) +- if auth: +- if ':' in auth: +- user, pw = auth.split(':', 1) +- creds = " --username=%s --password=%s" % (user, pw) +- else: +- creds = " --username=" + auth +- netloc = host +- parts = scheme, netloc, url, p, q, f +- url = urllib.parse.urlunparse(parts) +- self.info("Doing subversion checkout from %s to %s", url, filename) +- os.system("svn checkout%s -q %s %s" % (creds, url, filename)) +- return filename +- + @staticmethod +- def _vcs_split_rev_from_url(url, pop_prefix=False): +- scheme, netloc, path, query, frag = urllib.parse.urlsplit(url) +- +- scheme = scheme.split('+', 1)[-1] +- +- # Some fragment identification fails +- path = path.split('#', 1)[0] +- +- rev = None +- if '@' in path: +- path, rev = path.rsplit('@', 1) +- +- # Also, discard fragment +- url = urllib.parse.urlunsplit((scheme, netloc, path, query, '')) +- +- return url, rev +- +- def _download_git(self, url, filename): +- filename = filename.split('#', 1)[0] +- url, rev = self._vcs_split_rev_from_url(url, pop_prefix=True) +- +- self.info("Doing git clone from %s to %s", url, filename) +- os.system("git clone --quiet %s %s" % (url, filename)) ++ def _vcs_split_rev_from_url(url): ++ """ ++ Given a possible VCS URL, return a clean URL and resolved revision if any. + +- if rev is not None: +- self.info("Checking out %s", rev) +- os.system("(cd %s && git checkout --quiet %s)" % ( +- filename, +- rev, +- )) ++ >>> vsrfu = PackageIndex._vcs_split_rev_from_url ++ >>> vsrfu('git+https://github.com/pypa/setuptools@v69.0.0#egg-info=setuptools') ++ ('https://github.com/pypa/setuptools', 'v69.0.0') ++ >>> vsrfu('git+https://github.com/pypa/setuptools#egg-info=setuptools') ++ ('https://github.com/pypa/setuptools', None) ++ >>> vsrfu('http://foo/bar') ++ ('http://foo/bar', None) ++ """ ++ parts = urllib.parse.urlsplit(url) + +- return filename ++ clean_scheme = parts.scheme.split('+', 1)[-1] + +- def _download_hg(self, url, filename): +- filename = filename.split('#', 1)[0] +- url, rev = self._vcs_split_rev_from_url(url, pop_prefix=True) ++ # Some fragment identification fails ++ no_fragment_path, _, _ = parts.path.partition('#') + +- self.info("Doing hg clone from %s to %s", url, filename) +- os.system("hg clone --quiet %s %s" % (url, filename)) ++ pre, sep, post = no_fragment_path.rpartition('@') ++ clean_path, rev = (pre, post) if sep else (post, None) + +- if rev is not None: +- self.info("Updating to %s", rev) +- os.system("(cd %s && hg up -C -r %s >&-)" % ( +- filename, +- rev, +- )) ++ resolved = parts._replace( ++ scheme=clean_scheme, ++ path=clean_path, ++ # discard the fragment ++ fragment='', ++ ).geturl() + +- return filename ++ return resolved, rev + + def debug(self, msg, *args): + log.debug(msg, *args) diff --git a/SOURCES/RHEL-61138-nfsserver-also-stop-rpc-statd-for-nfsv4_only.patch b/SOURCES/RHEL-61138-nfsserver-also-stop-rpc-statd-for-nfsv4_only.patch new file mode 100644 index 0000000..73e2324 --- /dev/null +++ b/SOURCES/RHEL-61138-nfsserver-also-stop-rpc-statd-for-nfsv4_only.patch @@ -0,0 +1,38 @@ +From 38eaf00bc81af7530c56eba282918762a47a9326 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Thu, 19 Sep 2024 13:01:53 +0200 +Subject: [PATCH] nfsserver: also stop rpc-statd for nfsv4_only to avoid stop + failing in some cases + +E.g. nfs_no_notify=true nfsv4_only=true nfs_shared_infodir=/nfsmq/nfsinfo would cause a "Failed to unmount a bind mount" error +--- + heartbeat/nfsserver | 16 +++++++--------- + 1 file changed, 7 insertions(+), 9 deletions(-) + +diff --git a/heartbeat/nfsserver b/heartbeat/nfsserver +index 5793d7a70..fd9268afc 100755 +--- a/heartbeat/nfsserver ++++ b/heartbeat/nfsserver +@@ -947,15 +947,13 @@ nfsserver_stop () + sleep 1 + done + +- if ! ocf_is_true "$OCF_RESKEY_nfsv4_only"; then +- nfs_exec stop rpc-statd > /dev/null 2>&1 +- ocf_log info "Stop: rpc-statd" +- rpcinfo -t localhost 100024 > /dev/null 2>&1 +- rc=$? +- if [ "$rc" -eq "0" ]; then +- ocf_exit_reason "Failed to stop rpc-statd" +- return $OCF_ERR_GENERIC +- fi ++ nfs_exec stop rpc-statd > /dev/null 2>&1 ++ ocf_log info "Stop: rpc-statd" ++ rpcinfo -t localhost 100024 > /dev/null 2>&1 ++ rc=$? ++ if [ "$rc" -eq "0" ]; then ++ ocf_exit_reason "Failed to stop rpc-statd" ++ return $OCF_ERR_GENERIC + fi + + nfs_exec stop nfs-idmapd > /dev/null 2>&1 diff --git a/SOURCES/RHEL-69297-1-Filesystem-dont-kill-unrelated-processes.patch b/SOURCES/RHEL-69297-1-Filesystem-dont-kill-unrelated-processes.patch new file mode 100644 index 0000000..ca24f32 --- /dev/null +++ b/SOURCES/RHEL-69297-1-Filesystem-dont-kill-unrelated-processes.patch @@ -0,0 +1,22 @@ +From 4b09b3e467a7f8076bbf20f5b027efecf16303e7 Mon Sep 17 00:00:00 2001 +From: Gianluca Piccolo +Date: Thu, 6 Jun 2024 17:34:41 +0200 +Subject: [PATCH] Fix #1944 + +--- + heartbeat/Filesystem | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/Filesystem b/heartbeat/Filesystem +index a445349b9..59b6c1b51 100755 +--- a/heartbeat/Filesystem ++++ b/heartbeat/Filesystem +@@ -664,7 +664,7 @@ get_pids() + if [ "X${HOSTOS}" = "XOpenBSD" ];then + fstat | grep $dir | awk '{print $3}' + else +- $FUSER -m $dir 2>/dev/null ++ $FUSER -Mm $dir 2>/dev/null + fi + elif [ "$FORCE_UNMOUNT" = "safe" ]; then + procs=$(find /proc/[0-9]*/ -type l -lname "${dir}/*" -or -lname "${dir}" 2>/dev/null | awk -F/ '{print $3}') diff --git a/SOURCES/RHEL-69297-2-Filesystem-update-bsd-logic.patch b/SOURCES/RHEL-69297-2-Filesystem-update-bsd-logic.patch new file mode 100644 index 0000000..8299fa8 --- /dev/null +++ b/SOURCES/RHEL-69297-2-Filesystem-update-bsd-logic.patch @@ -0,0 +1,26 @@ +From c9ba6ac66ee27a70c69e1156f17aa6beac277bc5 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 7 Jun 2024 14:23:28 +0200 +Subject: [PATCH] Filesystem: use fuser -c on FreeBSD, as -m and -M are used + for other functionality + +--- + heartbeat/Filesystem | 4 +++- + 1 file changed, 3 insertions(+), 1 deletion(-) + +diff --git a/heartbeat/Filesystem b/heartbeat/Filesystem +index 59b6c1b51..88fe2e2eb 100755 +--- a/heartbeat/Filesystem ++++ b/heartbeat/Filesystem +@@ -661,8 +661,10 @@ get_pids() + fi + + if ocf_is_true "$FORCE_UNMOUNT"; then +- if [ "X${HOSTOS}" = "XOpenBSD" ];then ++ if [ "X${HOSTOS}" = "XOpenBSD" ]; then + fstat | grep $dir | awk '{print $3}' ++ elif [ "X${HOSTOS}" = "XFreeBSD" ]; then ++ $FUSER -c $dir 2>/dev/null + else + $FUSER -Mm $dir 2>/dev/null + fi diff --git a/SOURCES/RHEL-72956-1-openstack-cinder-volume-wait-for-volume-to-be-available.patch b/SOURCES/RHEL-72956-1-openstack-cinder-volume-wait-for-volume-to-be-available.patch new file mode 100644 index 0000000..5eb8beb --- /dev/null +++ b/SOURCES/RHEL-72956-1-openstack-cinder-volume-wait-for-volume-to-be-available.patch @@ -0,0 +1,63 @@ +From 71bc76dc4fa57726e80d0ddcc0bdcfe708af8763 Mon Sep 17 00:00:00 2001 +From: "Fabio M. Di Nitto" +Date: Thu, 5 Dec 2024 11:02:40 +0100 +Subject: [PATCH] openstack-cinder-volume: wait for volume to be available +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +monitor the vol till it´s attached to the host and avoid a race between +openstack APIs receiving the request and completing the operation. + +Signed-off-by: Fabio M. Di Nitto +--- + heartbeat/openstack-cinder-volume | 29 ++++++++++++++++++----------- + 1 file changed, 18 insertions(+), 11 deletions(-) + +diff --git a/heartbeat/openstack-cinder-volume b/heartbeat/openstack-cinder-volume +index 116442c41b..2b64d4d887 100755 +--- a/heartbeat/openstack-cinder-volume ++++ b/heartbeat/openstack-cinder-volume +@@ -141,17 +141,19 @@ osvol_monitor() { + + node_id=$(_get_node_id) + +- if [ "$__OCF_ACTION" = "monitor" ] && ocf_is_true $OCF_RESKEY_volume_local_check ; then +- # +- # Is the volue attached? +- # We check the local devices +- # +- short_volume_id=$(echo $OCF_RESKEY_volume_id | awk '{print substr($0, 0, 20)}') +- if lsblk /dev/disk/by-id/virtio-$short_volume_id 1>/dev/null 2>&1; then +- return $OCF_SUCCESS +- else +- ocf_log warn "$OCF_RESKEY_volume_id is not attached to instance $node_id" +- return $OCF_NOT_RUNNING ++ if ocf_is_true $OCF_RESKEY_volume_local_check ; then ++ if [ "$__OCF_ACTION" = "monitor" ] || [ "$__OCF_ACTION" = "start" ] ; then ++ # ++ # Is the volue attached? ++ # We check the local devices ++ # ++ short_volume_id=$(echo $OCF_RESKEY_volume_id | awk '{print substr($0, 0, 20)}') ++ if lsblk /dev/disk/by-id/virtio-$short_volume_id 1>/dev/null 2>&1; then ++ return $OCF_SUCCESS ++ else ++ ocf_log warn "$OCF_RESKEY_volume_id is not attached to instance $node_id" ++ return $OCF_NOT_RUNNING ++ fi + fi + fi + +@@ -247,6 +249,11 @@ osvol_start() { + return $OCF_ERR_GENERIC + fi + ++ while ! osvol_monitor; do ++ ocf_log info "Waiting for cinder volume $OCF_RESKEY_volume_id to appear on $node_id" ++ sleep 1 ++ done ++ + return $OCF_SUCCESS + } + diff --git a/SOURCES/RHEL-72956-2-openstack-cinder-volume-fix-detach-not-working-during-start-action.patch b/SOURCES/RHEL-72956-2-openstack-cinder-volume-fix-detach-not-working-during-start-action.patch new file mode 100644 index 0000000..079359b --- /dev/null +++ b/SOURCES/RHEL-72956-2-openstack-cinder-volume-fix-detach-not-working-during-start-action.patch @@ -0,0 +1,44 @@ +From d89b3fb29033c3a60eb0896033af5981c7b9f64a Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 10 Jan 2025 11:39:48 +0100 +Subject: [PATCH] openstack-cinder-volume: fix detach not working during + start-action after #2000 + +--- + heartbeat/openstack-cinder-volume | 8 ++++---- + 1 file changed, 4 insertions(+), 4 deletions(-) + +diff --git a/heartbeat/openstack-cinder-volume b/heartbeat/openstack-cinder-volume +index 2b64d4d88..5bb1acddd 100755 +--- a/heartbeat/openstack-cinder-volume ++++ b/heartbeat/openstack-cinder-volume +@@ -142,9 +142,9 @@ osvol_monitor() { + node_id=$(_get_node_id) + + if ocf_is_true $OCF_RESKEY_volume_local_check ; then +- if [ "$__OCF_ACTION" = "monitor" ] || [ "$__OCF_ACTION" = "start" ] ; then ++ if [ "$__OCF_ACTION" = "monitor" ] || [ "$1" = "quick" ]; then + # +- # Is the volue attached? ++ # Is the volume attached? + # We check the local devices + # + short_volume_id=$(echo $OCF_RESKEY_volume_id | awk '{print substr($0, 0, 20)}') +@@ -158,7 +158,7 @@ osvol_monitor() { + fi + + # +- # Is the volue attached? ++ # Is the volume attached? + # We use the API + # + result=$(run_openstackcli "volume show \ +@@ -249,7 +249,7 @@ osvol_start() { + return $OCF_ERR_GENERIC + fi + +- while ! osvol_monitor; do ++ while ! osvol_monitor quick; do + ocf_log info "Waiting for cinder volume $OCF_RESKEY_volume_id to appear on $node_id" + sleep 1 + done diff --git a/SOURCES/RHEL-79823-portblock-fix-version-detection.patch b/SOURCES/RHEL-79823-portblock-fix-version-detection.patch new file mode 100644 index 0000000..c70ecea --- /dev/null +++ b/SOURCES/RHEL-79823-portblock-fix-version-detection.patch @@ -0,0 +1,448 @@ +--- a/heartbeat/portblock 2025-02-20 14:54:18.047134471 +0100 ++++ b/heartbeat/portblock 2025-02-20 14:09:44.546869740 +0100 +@@ -25,6 +25,7 @@ + # Defaults + OCF_RESKEY_protocol_default="" + OCF_RESKEY_portno_default="" ++OCF_RESKEY_direction_default="in" + OCF_RESKEY_action_default="" + OCF_RESKEY_ip_default="0.0.0.0/0" + OCF_RESKEY_reset_local_on_unblock_stop_default="false" +@@ -33,6 +34,7 @@ + + : ${OCF_RESKEY_protocol=${OCF_RESKEY_protocol_default}} + : ${OCF_RESKEY_portno=${OCF_RESKEY_portno_default}} ++: ${OCF_RESKEY_direction=${OCF_RESKEY_direction_default}} + : ${OCF_RESKEY_action=${OCF_RESKEY_action_default}} + : ${OCF_RESKEY_ip=${OCF_RESKEY_ip_default}} + : ${OCF_RESKEY_reset_local_on_unblock_stop=${OCF_RESKEY_reset_local_on_unblock_stop_default}} +@@ -217,6 +219,18 @@ + Connection state file synchronization script + + ++ ++ ++ ++Whether to block incoming or outgoing traffic. Can be either "in", ++"out", or "both". ++If "in" is used, the incoming ports are blocked on the INPUT chain. ++If "out" is used, the outgoing ports are blocked on the OUTPUT chain. ++If "both" is used, both the incoming and outgoing ports are blocked. ++ ++Whether to block incoming or outgoing traffic, or both ++ ++ + + + +@@ -240,36 +254,73 @@ + # and disable us -- but we're still in some sense active... + # + +-#active_grep_pat {udp|tcp} portno,portno ++#active_grep_pat {udp|tcp} portno,portno ip {d|s} ++# d = look for destination ports ++# s = look for source ports + active_grep_pat() + { + w="[ ][ ]*" + any="0\\.0\\.0\\.0/0" +- echo "^DROP${w}${1}${w}--${w}${any}${w}${3}${w}multiport${w}dports${w}${2}\>" ++ src=$any dst=$3 ++ if [ "$4" = "s" ]; then ++ local src=$3 ++ local dst=$any ++ fi ++ # iptables 1.8.9 briefly broke the output format, returning the ++ # numeric protocol value instead of a string. Support both variants. ++ if [ "$1" = "tcp" ]; then ++ local prot="(tcp|6)" ++ else ++ local prot="(udp|17)" ++ fi ++ echo "^DROP${w}${prot}${w}--${w}${src}${w}${dst}${w}multiport${w}${4}ports${w}${2}$" + } + +-#chain_isactive {udp|tcp} portno,portno ip ++#chain_isactive {udp|tcp} portno,portno ip chain + chain_isactive() + { +- PAT=`active_grep_pat "$1" "$2" "$3"` +- $IPTABLES $wait -n -L INPUT | grep "$PAT" >/dev/null ++ [ "$4" = "OUTPUT" ] && ds="s" || ds="d" ++ PAT=$(active_grep_pat "$1" "$2" "$3" "$ds") ++ $IPTABLES $wait -n -L "$4" | grep -qE "$PAT" ++} ++ ++# netstat -tn and ss -Htn, split on whitespace and colon, ++# look very similar: ++# tcp 0 0 10.43.55.1 675 10.43.9.8 2049 ESTABLISHED ++# ESTAB 0 0 10.43.55.1 675 10.43.9.8 2049 ++# so we can write one awk script for both ++get_established_tcp_connections() ++{ ++ local columns ++ if [ -z "$1" ] ; then ++ columns='$4,$5, $6,$7' ++ else ++ # swap local and remote for "tickle_local" ++ columns='$6,$7, $4,$5' ++ fi ++ $ss_or_netstat | awk -F '[:[:space:]]+' ' ++ ( $8 == "ESTABLISHED" || $1 == "ESTAB" ) && $4 == "'$OCF_RESKEY_ip'" \ ++ {printf "%s:%s\t%s:%s\n", '"$columns"'}' + } + + save_tcp_connections() + { + [ -z "$OCF_RESKEY_tickle_dir" ] && return + statefile=$OCF_RESKEY_tickle_dir/$OCF_RESKEY_ip ++ # If we have _no_ sync script, we probably have a shared ++ # (or replicated) directory, and need to fsync, or we might ++ # end up with the just truncated file after failover, exactly ++ # when we need it. ++ # ++ # If we _do_ have a sync script, it is not that important whether ++ # the local state file is fsync'ed or not, the sync script is ++ # responsible to "atomically" communicate the state to the peer(s). + if [ -z "$OCF_RESKEY_sync_script" ]; then +- netstat -tn |awk -F '[:[:space:]]+' ' +- $8 == "ESTABLISHED" && $4 == "'$OCF_RESKEY_ip'" \ +- {printf "%s:%s\t%s:%s\n", $4,$5, $6,$7}' | +- dd of="$statefile".new conv=fsync status=none && +- mv "$statefile".new "$statefile" ++ get_established_tcp_connections | ++ dd of="$statefile".new conv=fsync status=none && ++ mv "$statefile".new "$statefile" + else +- netstat -tn |awk -F '[:[:space:]]+' ' +- $8 == "ESTABLISHED" && $4 == "'$OCF_RESKEY_ip'" \ +- {printf "%s:%s\t%s:%s\n", $4,$5, $6,$7}' \ +- > $statefile ++ get_established_tcp_connections > $statefile + $OCF_RESKEY_sync_script $statefile > /dev/null 2>&1 & + fi + } +@@ -277,7 +328,6 @@ + tickle_remote() + { + [ -z "$OCF_RESKEY_tickle_dir" ] && return +- echo 1 > /proc/sys/net/ipv4/tcp_tw_recycle + f=$OCF_RESKEY_tickle_dir/$OCF_RESKEY_ip + [ -r $f ] || return + $TICKLETCP -n 3 < $f +@@ -289,11 +339,6 @@ + f=$OCF_RESKEY_tickle_dir/$OCF_RESKEY_ip + [ -r $f ] || return + +- checkcmd="netstat -tn" +- if ! have_binary "netstat"; then +- checkcmd="ss -Htn" +- fi +- + # swap "local" and "remote" address, + # so we tickle ourselves. + # We set up a REJECT with tcp-reset before we do so, so we get rid of +@@ -302,122 +347,152 @@ + # the way if we switch-over and then switch-back in quick succession. + local i + awk '{ print $2, $1; }' $f | $TICKLETCP +- $checkcmd | grep -Fw $OCF_RESKEY_ip || return ++ $ss_or_netstat | grep -Fw $OCF_RESKEY_ip || return + for i in 0.1 0.5 1 2 4 ; do + sleep $i +- awk '{ print $2, $1; }' $f | $TICKLETCP +- $checkcmd | grep -Fw $OCF_RESKEY_ip || break ++ # now kill what is currently in the list, ++ # not what was recorded during last monitor ++ get_established_tcp_connections swap | $TICKLETCP ++ $ss_or_netstat | grep -Fw $OCF_RESKEY_ip || break + done + } + + SayActive() + { +- echo "$CMD DROP rule for INPUT chain [$*] is running (OK)" ++ ocf_log debug "$CMD DROP rule [$*] is running (OK)" + } + + SayConsideredActive() + { +- echo "$CMD DROP rule for INPUT chain [$*] considered to be running (OK)" ++ ocf_log debug "$CMD DROP rule [$*] considered to be running (OK)" + } + + SayInactive() + { +- echo "$CMD DROP rule for INPUT chain [$*] is inactive" ++ ocf_log debug "$CMD DROP rule [$*] is inactive" + } + +-#IptablesStatus {udp|tcp} portno,portno ip {block|unblock} ++#IptablesStatus {udp|tcp} portno,portno ip {in|out|both} {block|unblock} + IptablesStatus() { +- local rc +- rc=$OCF_ERR_GENERIC +- activewords="$CMD $1 $2 is running (OK)" +- if chain_isactive "$1" "$2" "$3"; then +- case $4 in +- block) +- SayActive $* +- rc=$OCF_SUCCESS +- ;; +- *) +- SayInactive $* +- rc=$OCF_NOT_RUNNING +- ;; +- esac +- else +- case $4 in +- block) +- if ha_pseudo_resource "${OCF_RESOURCE_INSTANCE}" status; then +- SayConsideredActive $* +- rc=$OCF_SUCCESS +- else +- SayInactive $* +- rc=$OCF_NOT_RUNNING +- fi +- ;; +- +- *) +- if ha_pseudo_resource "${OCF_RESOURCE_INSTANCE}" status; then +- SayActive $* +- #This is only run on real monitor events. +- save_tcp_connections +- rc=$OCF_SUCCESS +- else +- SayInactive $* +- rc=$OCF_NOT_RUNNING +- fi +- ;; +- esac +- fi +- +- return $rc ++ local rc ++ rc=$OCF_ERR_GENERIC ++ is_active=0 ++ if [ "$4" = "in" ] || [ "$4" = "both" ]; then ++ chain_isactive "$1" "$2" "$3" INPUT ++ is_active=$? ++ fi ++ if [ "$4" = "out" ] || [ "$4" = "both" ]; then ++ chain_isactive "$1" "$2" "$3" OUTPUT ++ r=$? ++ [ $r -gt $is_active ] && is_active=$r ++ fi ++ if [ $is_active -eq 0 ]; then ++ case $5 in ++ block) ++ SayActive $* ++ rc=$OCF_SUCCESS ++ ;; ++ *) ++ SayInactive $* ++ rc=$OCF_NOT_RUNNING ++ ;; ++ esac ++ else ++ case $5 in ++ block) ++ if ha_pseudo_resource "${OCF_RESOURCE_INSTANCE}" status; then ++ SayConsideredActive $* ++ rc=$OCF_SUCCESS ++ else ++ SayInactive $* ++ rc=$OCF_NOT_RUNNING ++ fi ++ ;; ++ *) ++ if ha_pseudo_resource "${OCF_RESOURCE_INSTANCE}" status; then ++ SayActive $* ++ #This is only run on real monitor events. ++ save_tcp_connections ++ rc=$OCF_SUCCESS ++ else ++ SayInactive $* ++ rc=$OCF_NOT_RUNNING ++ fi ++ ;; ++ esac ++ fi ++ return $rc + } + +-#IptablesBLOCK {udp|tcp} portno,portno ip +-IptablesBLOCK() ++#DoIptables {-I|-D} {udp|tcp} portno,portno ip chain ++DoIptables() + { +- local rc=0 +- local try_reset=false +- if [ "$1/$4/$__OCF_ACTION" = tcp/unblock/stop ] && +- ocf_is_true $reset_local_on_unblock_stop +- then +- try_reset=true +- fi +- if +- chain_isactive "$1" "$2" "$3" +- then +- : OK -- chain already active ++ op=$1 proto=$2 ports=$3 ip=$4 chain=$5 ++ active=0; chain_isactive "$proto" "$ports" "$ip" "$chain" && active=1 ++ want_active=0; [ "$op" = "-I" ] && want_active=1 ++ ocf_log debug "active: $active want_active: $want_active" ++ if [ $active -eq $want_active ] ; then ++ : Chain already in desired state + else +- if $try_reset ; then +- $IPTABLES $wait -I OUTPUT -p "$1" -s "$3" -m multiport --sports "$2" -j REJECT --reject-with tcp-reset +- tickle_local ++ [ "$chain" = "OUTPUT" ] && ds="s" || ds="d" ++ $IPTABLES $wait "$op" "$chain" -p "$proto" -${ds} "$ip" -m multiport --${ds}ports "$ports" -j DROP ++ fi ++} ++ ++#IptablesBLOCK {udp|tcp} portno,portno ip {in|out|both} {block|unblock} ++IptablesBLOCK() ++{ ++ local rc_in=0 ++ local rc_out=0 ++ if [ "$4" = "in" ] || [ "$4" = "both" ]; then ++ local try_reset=false ++ if [ "$1/$5/$__OCF_ACTION" = tcp/unblock/stop ] && ++ ocf_is_true $reset_local_on_unblock_stop ++ then ++ try_reset=true + fi +- $IPTABLES $wait -I INPUT -p "$1" -d "$3" -m multiport --dports "$2" -j DROP +- rc=$? +- if $try_reset ; then +- $IPTABLES $wait -D OUTPUT -p "$1" -s "$3" -m multiport --sports "$2" -j REJECT --reject-with tcp-reset ++ if ++ chain_isactive "$1" "$2" "$3" INPUT ++ then ++ : OK -- chain already active ++ else ++ if $try_reset ; then ++ $IPTABLES $wait -I OUTPUT -p "$1" -s "$3" -m multiport --sports "$2" -j REJECT --reject-with tcp-reset ++ tickle_local ++ fi ++ $IPTABLES $wait -I INPUT -p "$1" -d "$3" -m multiport --dports "$2" -j DROP ++ rc_in=$? ++ if $try_reset ; then ++ $IPTABLES $wait -D OUTPUT -p "$1" -s "$3" -m multiport --sports "$2" -j REJECT --reject-with tcp-reset ++ fi + fi + fi ++ if [ "$4" = "out" ] || [ "$4" = "both" ]; then ++ DoIptables -I "$1" "$2" "$3" OUTPUT ++ rc_out=$? ++ fi + +- return $rc ++ [ $rc_in -gt $rc_out ] && return $rc_in || return $rc_out + } + +-#IptablesUNBLOCK {udp|tcp} portno,portno ip ++#IptablesUNBLOCK {udp|tcp} portno,portno ip {in|out|both} + IptablesUNBLOCK() + { +- if +- chain_isactive "$1" "$2" "$3" +- then +- $IPTABLES $wait -D INPUT -p "$1" -d "$3" -m multiport --dports "$2" -j DROP +- else +- : Chain Not active ++ if [ "$4" = "in" ] || [ "$4" = "both" ]; then ++ DoIptables -D "$1" "$2" "$3" INPUT ++ fi ++ if [ "$4" = "out" ] || [ "$4" = "both" ]; then ++ DoIptables -D "$1" "$2" "$3" OUTPUT + fi + + return $? + } + +-#IptablesStart {udp|tcp} portno,portno ip {block|unblock} ++#IptablesStart {udp|tcp} portno,portno ip {in|out|both} {block|unblock} + IptablesStart() + { + ha_pseudo_resource "${OCF_RESOURCE_INSTANCE}" start +- case $4 in ++ case $5 in + block) IptablesBLOCK "$@";; + unblock) + IptablesUNBLOCK "$@" +@@ -432,11 +507,11 @@ + return $? + } + +-#IptablesStop {udp|tcp} portno,portno ip {block|unblock} ++#IptablesStop {udp|tcp} portno,portno ip {in|out|both} {block|unblock} + IptablesStop() + { + ha_pseudo_resource "${OCF_RESOURCE_INSTANCE}" stop +- case $4 in ++ case $5 in + block) IptablesUNBLOCK "$@";; + unblock) + save_tcp_connections +@@ -454,7 +529,7 @@ + CheckPort() { + # Examples of valid port: "1080", "1", "0080" + # Examples of invalid port: "1080bad", "0", "0000", "" +- echo $1 |egrep -qx '[0-9]+(:[0-9]+)?(,[0-9]+(:[0-9]+)?)*' ++ echo $1 | $EGREP -qx '[0-9]+(:[0-9]+)?(,[0-9]+(:[0-9]+)?)*' + } + + IptablesValidateAll() +@@ -543,7 +618,7 @@ + fi + + # iptables v1.4.20+ is required to use -w (wait) +-version=$(iptables -V | awk -F ' v' '{print $NF}') ++version=$(iptables -V | grep -oE '[0-9]+[\.0-9]+') + ocf_version_cmp "$version" "1.4.19.1" + if [ "$?" -eq "2" ]; then + wait="-w" +@@ -553,21 +628,36 @@ + + protocol=$OCF_RESKEY_protocol + portno=$OCF_RESKEY_portno ++direction=$OCF_RESKEY_direction + action=$OCF_RESKEY_action + ip=$OCF_RESKEY_ip + reset_local_on_unblock_stop=$OCF_RESKEY_reset_local_on_unblock_stop + ++ ++# If "tickle" is enabled, we need to record the list of currently established ++# connections during monitor. Use ss where available, and netstat otherwise. ++if [ -n "$OCF_RESKEY_tickle_dir" ] ; then ++ if have_binary ss ; then ++ ss_or_netstat="ss -Htn" ++ elif have_binary netstat ; then ++ ss_or_netstat="netstat -tn" ++ else ++ ocf_log err "Neither ss nor netstat found, but needed to record estblished connections." ++ exit $OCF_ERR_INSTALLED ++ fi ++fi ++ + case $1 in + start) +- IptablesStart $protocol $portno $ip $action ++ IptablesStart $protocol $portno $ip $direction $action + ;; + + stop) +- IptablesStop $protocol $portno $ip $action ++ IptablesStop $protocol $portno $ip $direction $action + ;; + + status|monitor) +- IptablesStatus $protocol $portno $ip $action ++ IptablesStatus $protocol $portno $ip $direction $action + ;; + + validate-all) diff --git a/SOURCES/RHEL-81960-1-aws-agents-reuse-imds-token-until-it-expires.patch b/SOURCES/RHEL-81960-1-aws-agents-reuse-imds-token-until-it-expires.patch new file mode 100644 index 0000000..e3e5dc8 --- /dev/null +++ b/SOURCES/RHEL-81960-1-aws-agents-reuse-imds-token-until-it-expires.patch @@ -0,0 +1,455 @@ +From 61cec34a754017537c61e79cd1212f2688c32429 Mon Sep 17 00:00:00 2001 +From: harshkiprofile <83770157+harshkiprofile@users.noreply.github.com> +Date: Mon, 4 Nov 2024 12:19:10 +0530 +Subject: [PATCH 1/7] Introduce a new shell function to reuse IMDS token + +--- + heartbeat/ocf-shellfuncs.in | 31 +++++++++++++++++++++++++++++++ + 1 file changed, 31 insertions(+) + +diff --git a/heartbeat/ocf-shellfuncs.in b/heartbeat/ocf-shellfuncs.in +index 5c4bb3264..0c4632cf9 100644 +--- a/heartbeat/ocf-shellfuncs.in ++++ b/heartbeat/ocf-shellfuncs.in +@@ -1111,3 +1111,34 @@ ocf_is_true "$OCF_TRACE_RA" && ocf_start_trace + if ocf_is_true "$HA_use_logd"; then + : ${HA_LOGD:=yes} + fi ++ ++# File to store the token and timestamp ++TOKEN_FILE="/tmp/.imds_token" ++TOKEN_LIFETIME=21600 # Token lifetime in seconds (6 hours) ++TOKEN_EXPIRY_THRESHOLD=3600 # Renew token if less than 60 minutes (1 hour) remaining ++ ++# Function to fetch a new token ++fetch_new_token() { ++ TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: $TOKEN_LIFETIME") ++ echo "$TOKEN $(date +%s)" > "$TOKEN_FILE" ++ echo "$TOKEN" ++} ++ ++# Function to retrieve or renew the token ++get_token() { ++ if [[ -f "$TOKEN_FILE" ]]; then ++ read -r STORED_TOKEN STORED_TIMESTAMP < "$TOKEN_FILE" ++ CURRENT_TIME=$(date +%s) ++ ELAPSED_TIME=$((CURRENT_TIME - STORED_TIMESTAMP)) ++ ++ if (( ELAPSED_TIME < (TOKEN_LIFETIME - TOKEN_EXPIRY_THRESHOLD) )); then ++ # Token is still valid ++ echo "$STORED_TOKEN" ++ return ++ fi ++ fi ++ # Fetch a new token if not valid ++ fetch_new_token ++} ++ ++ + +From 00629fa44cb7a8dd1045fc8cad755e1d0c808476 Mon Sep 17 00:00:00 2001 +From: harshkiprofile <83770157+harshkiprofile@users.noreply.github.com> +Date: Mon, 4 Nov 2024 12:21:18 +0530 +Subject: [PATCH 2/7] Utilize the get_token function to reuse the token + +--- + heartbeat/aws-vpc-move-ip | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/aws-vpc-move-ip b/heartbeat/aws-vpc-move-ip +index 6115e5ba8..fbeb2ee64 100755 +--- a/heartbeat/aws-vpc-move-ip ++++ b/heartbeat/aws-vpc-move-ip +@@ -270,7 +270,7 @@ ec2ip_validate() { + fi + fi + +- TOKEN=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "--show-error -sX PUT -H 'X-aws-ec2-metadata-token-ttl-seconds: 21600'" "http://169.254.169.254/latest/api/token") ++ TOKEN=$(get_token) + [ $? -ne 0 ] && exit $OCF_ERR_GENERIC + EC2_INSTANCE_ID=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "--show-error -s -H 'X-aws-ec2-metadata-token: $TOKEN'" "http://169.254.169.254/latest/meta-data/instance-id") + [ $? -ne 0 ] && exit $OCF_ERR_GENERIC + +From 36126cdcb90ad617ecfce03d986550907732aa4f Mon Sep 17 00:00:00 2001 +From: harshkiprofile <83770157+harshkiprofile@users.noreply.github.com> +Date: Mon, 4 Nov 2024 12:22:16 +0530 +Subject: [PATCH 3/7] Utilize to get_token function to reuse the token + +--- + heartbeat/awsvip | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/awsvip b/heartbeat/awsvip +index f2b238a0f..ca19ac086 100755 +--- a/heartbeat/awsvip ++++ b/heartbeat/awsvip +@@ -266,7 +266,7 @@ if [ -n "${OCF_RESKEY_region}" ]; then + AWSCLI_CMD="$AWSCLI_CMD --region ${OCF_RESKEY_region}" + fi + SECONDARY_PRIVATE_IP="${OCF_RESKEY_secondary_private_ip}" +-TOKEN=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "--show-error -sX PUT -H 'X-aws-ec2-metadata-token-ttl-seconds: 21600'" "http://169.254.169.254/latest/api/token") ++TOKEN=$(get_token) + [ $? -ne 0 ] && exit $OCF_ERR_GENERIC + INSTANCE_ID=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "--show-error -s -H 'X-aws-ec2-metadata-token: $TOKEN'" "http://169.254.169.254/latest/meta-data/instance-id") + [ $? -ne 0 ] && exit $OCF_ERR_GENERIC + +From dcd0050df5ba94905bc71d38b05cbb93f5687b61 Mon Sep 17 00:00:00 2001 +From: harshkiprofile +Date: Mon, 4 Nov 2024 20:05:33 +0530 +Subject: [PATCH 4/7] Move token renewal function to aws.sh for reuse in AWS + agent scripts + +--- + heartbeat/Makefile.am | 1 + + heartbeat/aws-vpc-move-ip | 1 + + heartbeat/aws-vpc-route53.in | 3 ++- + heartbeat/aws.sh | 46 ++++++++++++++++++++++++++++++++++++ + heartbeat/awseip | 3 ++- + heartbeat/awsvip | 1 + + heartbeat/ocf-shellfuncs.in | 33 +------------------------- + 7 files changed, 54 insertions(+), 34 deletions(-) + create mode 100644 heartbeat/aws.sh + +diff --git a/heartbeat/Makefile.am b/heartbeat/Makefile.am +index 409847970..655740f14 100644 +--- a/heartbeat/Makefile.am ++++ b/heartbeat/Makefile.am +@@ -218,6 +218,7 @@ ocfcommon_DATA = ocf-shellfuncs \ + ocf-rarun \ + ocf-distro \ + apache-conf.sh \ ++ aws.sh \ + http-mon.sh \ + sapdb-nosha.sh \ + sapdb.sh \ +diff --git a/heartbeat/aws-vpc-move-ip b/heartbeat/aws-vpc-move-ip +index fbeb2ee64..f4b0492f2 100755 +--- a/heartbeat/aws-vpc-move-ip ++++ b/heartbeat/aws-vpc-move-ip +@@ -33,6 +33,7 @@ + + : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} + . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ++. ${OCF_FUNCTIONS_DIR}/aws.sh + + # Defaults + OCF_RESKEY_awscli_default="/usr/bin/aws" +diff --git a/heartbeat/aws-vpc-route53.in b/heartbeat/aws-vpc-route53.in +index eba2ed95c..f7e756782 100644 +--- a/heartbeat/aws-vpc-route53.in ++++ b/heartbeat/aws-vpc-route53.in +@@ -43,6 +43,7 @@ + + : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} + . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ++. ${OCF_FUNCTIONS_DIR}/aws.sh + + # Defaults + OCF_RESKEY_awscli_default="/usr/bin/aws" +@@ -377,7 +378,7 @@ r53_monitor() { + _get_ip() { + case $OCF_RESKEY_ip in + local|public) +- TOKEN=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "--show-error -sX PUT -H 'X-aws-ec2-metadata-token-ttl-seconds: 21600'" "http://169.254.169.254/latest/api/token") ++ TOKEN=$(get_token) + [ $? -ne 0 ] && exit $OCF_ERR_GENERIC + IPADDRESS=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "--show-error -s -H 'X-aws-ec2-metadata-token: $TOKEN'" "http://169.254.169.254/latest/meta-data/${OCF_RESKEY_ip}-ipv4") + [ $? -ne 0 ] && exit $OCF_ERR_GENERIC +diff --git a/heartbeat/aws.sh b/heartbeat/aws.sh +new file mode 100644 +index 000000000..fc557109c +--- /dev/null ++++ b/heartbeat/aws.sh +@@ -0,0 +1,46 @@ ++#!/bin/sh ++# ++# ++# AWS Helper Scripts ++# ++# ++ ++: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} ++. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ++ ++# Defaults ++OCF_RESKEY_curl_retries_default="3" ++OCF_RESKEY_curl_sleep_default="1" ++ ++: ${OCF_RESKEY_curl_retries=${OCF_RESKEY_curl_retries_default}} ++: ${OCF_RESKEY_curl_sleep=${OCF_RESKEY_curl_sleep_default}} ++ ++# Function to enable reusable IMDS token retrieval for efficient repeated access ++# File to store the token and timestamp ++TOKEN_FILE="/tmp/.imds_token" ++TOKEN_LIFETIME=21600 # Token lifetime in seconds (6 hours) ++TOKEN_EXPIRY_THRESHOLD=3600 # Renew token if less than 60 minutes (1 hour) remaining ++ ++# Function to fetch a new token ++fetch_new_token() { ++ TOKEN=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "--show-error -sX PUT -H 'X-aws-ec2-metadata-token-ttl-seconds: $TOKEN_LIFETIME'" "http://169.254.169.254/latest/api/token") ++ echo "$TOKEN $(date +%s)" > "$TOKEN_FILE" ++ echo "$TOKEN" ++} ++ ++# Function to retrieve or renew the token ++get_token() { ++ if [ -f "$TOKEN_FILE" ]; then ++ read -r STORED_TOKEN STORED_TIMESTAMP < "$TOKEN_FILE" ++ CURRENT_TIME=$(date +%s) ++ ELAPSED_TIME=$((CURRENT_TIME - STORED_TIMESTAMP)) ++ ++ if (( ELAPSED_TIME < (TOKEN_LIFETIME - TOKEN_EXPIRY_THRESHOLD) )); then ++ # Token is still valid ++ echo "$STORED_TOKEN" ++ return ++ fi ++ fi ++ # Fetch a new token if not valid ++ fetch_new_token ++} +\ No newline at end of file +diff --git a/heartbeat/awseip b/heartbeat/awseip +index ffb6223a1..049c2e566 100755 +--- a/heartbeat/awseip ++++ b/heartbeat/awseip +@@ -38,6 +38,7 @@ + + : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} + . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ++. ${OCF_FUNCTIONS_DIR}/aws.sh + + ####################################################################### + +@@ -306,7 +307,7 @@ fi + ELASTIC_IP="${OCF_RESKEY_elastic_ip}" + ALLOCATION_ID="${OCF_RESKEY_allocation_id}" + PRIVATE_IP_ADDRESS="${OCF_RESKEY_private_ip_address}" +-TOKEN=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "--show-error -sX PUT -H 'X-aws-ec2-metadata-token-ttl-seconds: 21600'" "http://169.254.169.254/latest/api/token") ++TOKEN=$(get_token) + [ $? -ne 0 ] && exit $OCF_ERR_GENERIC + INSTANCE_ID=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "--show-error -s -H 'X-aws-ec2-metadata-token: $TOKEN'" "http://169.254.169.254/latest/meta-data/instance-id") + [ $? -ne 0 ] && exit $OCF_ERR_GENERIC +diff --git a/heartbeat/awsvip b/heartbeat/awsvip +index ca19ac086..de67981d8 100755 +--- a/heartbeat/awsvip ++++ b/heartbeat/awsvip +@@ -37,6 +37,7 @@ + + : ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat} + . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs ++. ${OCF_FUNCTIONS_DIR}/aws.sh + + ####################################################################### + +diff --git a/heartbeat/ocf-shellfuncs.in b/heartbeat/ocf-shellfuncs.in +index 0c4632cf9..922c6ea45 100644 +--- a/heartbeat/ocf-shellfuncs.in ++++ b/heartbeat/ocf-shellfuncs.in +@@ -1110,35 +1110,4 @@ ocf_is_true "$OCF_TRACE_RA" && ocf_start_trace + # pacemaker sets HA_use_logd, some others use HA_LOGD :/ + if ocf_is_true "$HA_use_logd"; then + : ${HA_LOGD:=yes} +-fi +- +-# File to store the token and timestamp +-TOKEN_FILE="/tmp/.imds_token" +-TOKEN_LIFETIME=21600 # Token lifetime in seconds (6 hours) +-TOKEN_EXPIRY_THRESHOLD=3600 # Renew token if less than 60 minutes (1 hour) remaining +- +-# Function to fetch a new token +-fetch_new_token() { +- TOKEN=$(curl -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: $TOKEN_LIFETIME") +- echo "$TOKEN $(date +%s)" > "$TOKEN_FILE" +- echo "$TOKEN" +-} +- +-# Function to retrieve or renew the token +-get_token() { +- if [[ -f "$TOKEN_FILE" ]]; then +- read -r STORED_TOKEN STORED_TIMESTAMP < "$TOKEN_FILE" +- CURRENT_TIME=$(date +%s) +- ELAPSED_TIME=$((CURRENT_TIME - STORED_TIMESTAMP)) +- +- if (( ELAPSED_TIME < (TOKEN_LIFETIME - TOKEN_EXPIRY_THRESHOLD) )); then +- # Token is still valid +- echo "$STORED_TOKEN" +- return +- fi +- fi +- # Fetch a new token if not valid +- fetch_new_token +-} +- +- ++fi +\ No newline at end of file + +From 9f7be201923c8eab1b121f2067ed74a69841cf8a Mon Sep 17 00:00:00 2001 +From: harshkiprofile +Date: Tue, 5 Nov 2024 19:12:34 +0530 +Subject: [PATCH 5/7] Refactor to use common temp path and update shell syntax + +--- + heartbeat/Makefile.am | 2 +- + heartbeat/aws.sh | 4 ++-- + 2 files changed, 3 insertions(+), 3 deletions(-) + +diff --git a/heartbeat/Makefile.am b/heartbeat/Makefile.am +index 655740f14..8352f3a3d 100644 +--- a/heartbeat/Makefile.am ++++ b/heartbeat/Makefile.am +@@ -218,7 +218,7 @@ ocfcommon_DATA = ocf-shellfuncs \ + ocf-rarun \ + ocf-distro \ + apache-conf.sh \ +- aws.sh \ ++ aws.sh \ + http-mon.sh \ + sapdb-nosha.sh \ + sapdb.sh \ +diff --git a/heartbeat/aws.sh b/heartbeat/aws.sh +index fc557109c..c77f93b91 100644 +--- a/heartbeat/aws.sh ++++ b/heartbeat/aws.sh +@@ -17,7 +17,7 @@ OCF_RESKEY_curl_sleep_default="1" + + # Function to enable reusable IMDS token retrieval for efficient repeated access + # File to store the token and timestamp +-TOKEN_FILE="/tmp/.imds_token" ++TOKEN_FILE="${HA_RSCTMP}/.aws_imds_token" + TOKEN_LIFETIME=21600 # Token lifetime in seconds (6 hours) + TOKEN_EXPIRY_THRESHOLD=3600 # Renew token if less than 60 minutes (1 hour) remaining + +@@ -35,7 +35,7 @@ get_token() { + CURRENT_TIME=$(date +%s) + ELAPSED_TIME=$((CURRENT_TIME - STORED_TIMESTAMP)) + +- if (( ELAPSED_TIME < (TOKEN_LIFETIME - TOKEN_EXPIRY_THRESHOLD) )); then ++ if [ "$ELAPSED_TIME" -lt "$((TOKEN_LIFETIME - TOKEN_EXPIRY_THRESHOLD))" ]; then + # Token is still valid + echo "$STORED_TOKEN" + return + +From 4f61048064d1df3bebdb5c1441cf0020f213c01b Mon Sep 17 00:00:00 2001 +From: harshkiprofile +Date: Tue, 5 Nov 2024 19:30:15 +0530 +Subject: [PATCH 6/7] Consolidate curl_retry and curl_sleep variable to a + single location in aws.sh + +--- + heartbeat/aws-vpc-move-ip | 4 ---- + heartbeat/aws-vpc-route53.in | 4 ---- + heartbeat/awseip | 4 ---- + heartbeat/awsvip | 4 ---- + 4 files changed, 16 deletions(-) + +diff --git a/heartbeat/aws-vpc-move-ip b/heartbeat/aws-vpc-move-ip +index f4b0492f2..3aa9ceb02 100755 +--- a/heartbeat/aws-vpc-move-ip ++++ b/heartbeat/aws-vpc-move-ip +@@ -48,8 +48,6 @@ OCF_RESKEY_interface_default="eth0" + OCF_RESKEY_iflabel_default="" + OCF_RESKEY_monapi_default="false" + OCF_RESKEY_lookup_type_default="InstanceId" +-OCF_RESKEY_curl_retries_default="3" +-OCF_RESKEY_curl_sleep_default="1" + + : ${OCF_RESKEY_awscli=${OCF_RESKEY_awscli_default}} + : ${OCF_RESKEY_auth_type=${OCF_RESKEY_auth_type_default}} +@@ -63,8 +61,6 @@ OCF_RESKEY_curl_sleep_default="1" + : ${OCF_RESKEY_iflabel=${OCF_RESKEY_iflabel_default}} + : ${OCF_RESKEY_monapi=${OCF_RESKEY_monapi_default}} + : ${OCF_RESKEY_lookup_type=${OCF_RESKEY_lookup_type_default}} +-: ${OCF_RESKEY_curl_retries=${OCF_RESKEY_curl_retries_default}} +-: ${OCF_RESKEY_curl_sleep=${OCF_RESKEY_curl_sleep_default}} + ####################################################################### + + +diff --git a/heartbeat/aws-vpc-route53.in b/heartbeat/aws-vpc-route53.in +index f7e756782..85c8de3c1 100644 +--- a/heartbeat/aws-vpc-route53.in ++++ b/heartbeat/aws-vpc-route53.in +@@ -54,8 +54,6 @@ OCF_RESKEY_hostedzoneid_default="" + OCF_RESKEY_fullname_default="" + OCF_RESKEY_ip_default="local" + OCF_RESKEY_ttl_default=10 +-OCF_RESKEY_curl_retries_default="3" +-OCF_RESKEY_curl_sleep_default="1" + + : ${OCF_RESKEY_awscli=${OCF_RESKEY_awscli_default}} + : ${OCF_RESKEY_auth_type=${OCF_RESKEY_auth_type_default}} +@@ -65,8 +63,6 @@ OCF_RESKEY_curl_sleep_default="1" + : ${OCF_RESKEY_fullname:=${OCF_RESKEY_fullname_default}} + : ${OCF_RESKEY_ip:=${OCF_RESKEY_ip_default}} + : ${OCF_RESKEY_ttl:=${OCF_RESKEY_ttl_default}} +-: ${OCF_RESKEY_curl_retries=${OCF_RESKEY_curl_retries_default}} +-: ${OCF_RESKEY_curl_sleep=${OCF_RESKEY_curl_sleep_default}} + + usage() { + cat <<-EOT +diff --git a/heartbeat/awseip b/heartbeat/awseip +index 049c2e566..4b1c3bc6a 100755 +--- a/heartbeat/awseip ++++ b/heartbeat/awseip +@@ -50,16 +50,12 @@ OCF_RESKEY_auth_type_default="key" + OCF_RESKEY_profile_default="default" + OCF_RESKEY_region_default="" + OCF_RESKEY_api_delay_default="3" +-OCF_RESKEY_curl_retries_default="3" +-OCF_RESKEY_curl_sleep_default="1" + + : ${OCF_RESKEY_awscli=${OCF_RESKEY_awscli_default}} + : ${OCF_RESKEY_auth_type=${OCF_RESKEY_auth_type_default}} + : ${OCF_RESKEY_profile=${OCF_RESKEY_profile_default}} + : ${OCF_RESKEY_region=${OCF_RESKEY_region_default}} + : ${OCF_RESKEY_api_delay=${OCF_RESKEY_api_delay_default}} +-: ${OCF_RESKEY_curl_retries=${OCF_RESKEY_curl_retries_default}} +-: ${OCF_RESKEY_curl_sleep=${OCF_RESKEY_curl_sleep_default}} + + meta_data() { + cat < +Date: Tue, 5 Nov 2024 20:50:24 +0530 +Subject: [PATCH 7/7] aws.sh needs to added to be symlinkstargets in + doc/man/Makefile.am + +--- + doc/man/Makefile.am | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/doc/man/Makefile.am b/doc/man/Makefile.am +index ef7639bff..447f5cba3 100644 +--- a/doc/man/Makefile.am ++++ b/doc/man/Makefile.am +@@ -42,7 +42,7 @@ radir = $(abs_top_builddir)/heartbeat + # required for out-of-tree build + symlinkstargets = \ + ocf-distro ocf.py ocf-rarun ocf-returncodes \ +- findif.sh apache-conf.sh http-mon.sh mysql-common.sh \ ++ findif.sh apache-conf.sh aws.sh http-mon.sh mysql-common.sh \ + nfsserver-redhat.sh ora-common.sh + + preptree: diff --git a/SOURCES/RHEL-81960-2-aws-agents-reuse-imds-token-improvements.patch b/SOURCES/RHEL-81960-2-aws-agents-reuse-imds-token-improvements.patch new file mode 100644 index 0000000..2ba9acf --- /dev/null +++ b/SOURCES/RHEL-81960-2-aws-agents-reuse-imds-token-improvements.patch @@ -0,0 +1,161 @@ +From cc5ffa5e599c974c426e93faa821b342e96b916d Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 11 Nov 2024 12:46:27 +0100 +Subject: [PATCH 1/2] aws.sh: chmod 600 $TOKEN_FILE, add get_instance_id() with + DMI support, and use get_instance_id() in AWS agents + +--- + heartbeat/aws-vpc-move-ip | 2 +- + heartbeat/aws.sh | 30 +++++++++++++++++++++++++++--- + heartbeat/awseip | 2 +- + heartbeat/awsvip | 2 +- + 4 files changed, 30 insertions(+), 6 deletions(-) + +diff --git a/heartbeat/aws-vpc-move-ip b/heartbeat/aws-vpc-move-ip +index 3aa9ceb02..09ae68b57 100755 +--- a/heartbeat/aws-vpc-move-ip ++++ b/heartbeat/aws-vpc-move-ip +@@ -269,7 +269,7 @@ ec2ip_validate() { + + TOKEN=$(get_token) + [ $? -ne 0 ] && exit $OCF_ERR_GENERIC +- EC2_INSTANCE_ID=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "--show-error -s -H 'X-aws-ec2-metadata-token: $TOKEN'" "http://169.254.169.254/latest/meta-data/instance-id") ++ EC2_INSTANCE_ID=$(get_instance_id) + [ $? -ne 0 ] && exit $OCF_ERR_GENERIC + + if [ -z "${EC2_INSTANCE_ID}" ]; then +diff --git a/heartbeat/aws.sh b/heartbeat/aws.sh +index c77f93b91..9cd343c16 100644 +--- a/heartbeat/aws.sh ++++ b/heartbeat/aws.sh +@@ -9,8 +9,8 @@ + . ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs + + # Defaults +-OCF_RESKEY_curl_retries_default="3" +-OCF_RESKEY_curl_sleep_default="1" ++OCF_RESKEY_curl_retries_default="4" ++OCF_RESKEY_curl_sleep_default="3" + + : ${OCF_RESKEY_curl_retries=${OCF_RESKEY_curl_retries_default}} + : ${OCF_RESKEY_curl_sleep=${OCF_RESKEY_curl_sleep_default}} +@@ -20,11 +20,13 @@ OCF_RESKEY_curl_sleep_default="1" + TOKEN_FILE="${HA_RSCTMP}/.aws_imds_token" + TOKEN_LIFETIME=21600 # Token lifetime in seconds (6 hours) + TOKEN_EXPIRY_THRESHOLD=3600 # Renew token if less than 60 minutes (1 hour) remaining ++DMI_FILE="/sys/devices/virtual/dmi/id/board_asset_tag" # Only supported on nitro-based instances. + + # Function to fetch a new token + fetch_new_token() { + TOKEN=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "--show-error -sX PUT -H 'X-aws-ec2-metadata-token-ttl-seconds: $TOKEN_LIFETIME'" "http://169.254.169.254/latest/api/token") + echo "$TOKEN $(date +%s)" > "$TOKEN_FILE" ++ chmod 600 "$TOKEN_FILE" + echo "$TOKEN" + } + +@@ -43,4 +45,26 @@ get_token() { + fi + # Fetch a new token if not valid + fetch_new_token +-} +\ No newline at end of file ++} ++ ++get_instance_id() { ++ local INSTANCE_ID ++ ++ # Try to get the EC2 instance ID from DMI first before falling back to IMDS. ++ ocf_log debug "EC2: Attempt to get EC2 Instance ID from local file." ++ if [ -r "$DMI_FILE" ] && [ -s "$DMI_FILE" ]; then ++ INSTANCE_ID="$(cat "$DMI_FILE")" ++ case "$INSTANCE_ID" in ++ i-0*) echo "$INSTANCE_ID"; return "$OCF_SUCCESS" ;; ++ esac ++ fi ++ ++ INSTANCE_ID=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "--show-error -s -H 'X-aws-ec2-metadata-token: $TOKEN'" "http://169.254.169.254/latest/meta-data/instance-id") ++ if [ $? -ne 0 ]; then ++ ocf_exit_reason "Failed to get EC2 Instance ID" ++ exit $OCF_ERR_GENERIC ++ fi ++ ++ echo "$INSTANCE_ID" ++ return "$OCF_SUCCESS" ++} +diff --git a/heartbeat/awseip b/heartbeat/awseip +index 4b1c3bc6a..7f38376dc 100755 +--- a/heartbeat/awseip ++++ b/heartbeat/awseip +@@ -305,7 +305,7 @@ ALLOCATION_ID="${OCF_RESKEY_allocation_id}" + PRIVATE_IP_ADDRESS="${OCF_RESKEY_private_ip_address}" + TOKEN=$(get_token) + [ $? -ne 0 ] && exit $OCF_ERR_GENERIC +-INSTANCE_ID=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "--show-error -s -H 'X-aws-ec2-metadata-token: $TOKEN'" "http://169.254.169.254/latest/meta-data/instance-id") ++INSTANCE_ID=$(get_instance_id) + [ $? -ne 0 ] && exit $OCF_ERR_GENERIC + + case $__OCF_ACTION in +diff --git a/heartbeat/awsvip b/heartbeat/awsvip +index 8c71e7fac..0856ac5e4 100755 +--- a/heartbeat/awsvip ++++ b/heartbeat/awsvip +@@ -265,7 +265,7 @@ fi + SECONDARY_PRIVATE_IP="${OCF_RESKEY_secondary_private_ip}" + TOKEN=$(get_token) + [ $? -ne 0 ] && exit $OCF_ERR_GENERIC +-INSTANCE_ID=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "--show-error -s -H 'X-aws-ec2-metadata-token: $TOKEN'" "http://169.254.169.254/latest/meta-data/instance-id") ++INSTANCE_ID=$(get_instance_id) + [ $? -ne 0 ] && exit $OCF_ERR_GENERIC + MAC_ADDRESS=$(curl_retry "$OCF_RESKEY_curl_retries" "$OCF_RESKEY_curl_sleep" "--show-error -s -H 'X-aws-ec2-metadata-token: $TOKEN'" "http://169.254.169.254/latest/meta-data/mac") + [ $? -ne 0 ] && exit $OCF_ERR_GENERIC + +From b8d3ecc6a8ce4baf4b28d02978dd573728ccf5fa Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Mon, 18 Nov 2024 11:10:42 +0100 +Subject: [PATCH 2/2] aws.sh/ocf-shellfuncs: add ability to fresh token if it's + invalid + +--- + heartbeat/aws.sh | 1 + + heartbeat/ocf-shellfuncs.in | 11 ++++++++++- + 2 files changed, 11 insertions(+), 1 deletion(-) + +diff --git a/heartbeat/aws.sh b/heartbeat/aws.sh +index 9cd343c16..64f2e13a7 100644 +--- a/heartbeat/aws.sh ++++ b/heartbeat/aws.sh +@@ -18,6 +18,7 @@ OCF_RESKEY_curl_sleep_default="3" + # Function to enable reusable IMDS token retrieval for efficient repeated access + # File to store the token and timestamp + TOKEN_FILE="${HA_RSCTMP}/.aws_imds_token" ++TOKEN_FUNC="fetch_new_token" # Used by curl_retry() if saved token is invalid + TOKEN_LIFETIME=21600 # Token lifetime in seconds (6 hours) + TOKEN_EXPIRY_THRESHOLD=3600 # Renew token if less than 60 minutes (1 hour) remaining + DMI_FILE="/sys/devices/virtual/dmi/id/board_asset_tag" # Only supported on nitro-based instances. +diff --git a/heartbeat/ocf-shellfuncs.in b/heartbeat/ocf-shellfuncs.in +index 922c6ea45..8e51fa3c8 100644 +--- a/heartbeat/ocf-shellfuncs.in ++++ b/heartbeat/ocf-shellfuncs.in +@@ -697,6 +697,15 @@ curl_retry() + + ocf_log debug "result: $result" + [ $rc -eq 0 ] && break ++ if [ -n "$TOKEN" ] && [ -n "$TOKEN_FILE" ] && \ ++ [ -f "$TOKEN_FILE" ] && [ -n "$TOKEN_FUNC" ] && \ ++ echo "$result" | grep -q "The requested URL returned error: 401$"; then ++ local OLD_TOKEN="$TOKEN" ++ ocf_log err "Token invalid. Getting new token." ++ TOKEN=$($TOKEN_FUNC) ++ [ $? -ne 0 ] && exit $OCF_ERR_GENERIC ++ args=$(echo "$args" | sed "s/$OLD_TOKEN/$TOKEN/") ++ fi + sleep $sleep + done + +@@ -1110,4 +1119,4 @@ ocf_is_true "$OCF_TRACE_RA" && ocf_start_trace + # pacemaker sets HA_use_logd, some others use HA_LOGD :/ + if ocf_is_true "$HA_use_logd"; then + : ${HA_LOGD:=yes} +-fi +\ No newline at end of file ++fi diff --git a/SOURCES/RHEL-85048-tomcat-fix-CATALINA_PID-not-set-and-parameter-defaults.patch b/SOURCES/RHEL-85048-tomcat-fix-CATALINA_PID-not-set-and-parameter-defaults.patch new file mode 100644 index 0000000..fa236bb --- /dev/null +++ b/SOURCES/RHEL-85048-tomcat-fix-CATALINA_PID-not-set-and-parameter-defaults.patch @@ -0,0 +1,72 @@ +From f6a5f38405a93ab88e887aa657ee79593d1a4485 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Wed, 26 Mar 2025 09:48:06 +0100 +Subject: [PATCH 1/2] tomcat: fix CATALINA_PID not set issue + +--- + heartbeat/tomcat | 10 ++++++---- + 1 file changed, 6 insertions(+), 4 deletions(-) + +diff --git a/heartbeat/tomcat b/heartbeat/tomcat +index fa2715140b..6d47980296 100755 +--- a/heartbeat/tomcat ++++ b/heartbeat/tomcat +@@ -695,10 +695,12 @@ CATALINA_BASE="${OCF_RESKEY_catalina_base-${OCF_RESKEY_catalina_home}}" + CATALINA_OUT="${OCF_RESKEY_catalina_out}" + + CATALINA_PID=$OCF_RESKEY_catalina_pid +-if [ -z "$CATALINA_PID" ] && [ "$__OCF_ACTION" = "start" ]; then +- mkdir -p "${HA_RSCTMP}/${TOMCAT_NAME}_tomcatstate/" +- if [ "${RESOURCE_TOMCAT_USER}" != "root" ]; then +- chown ${RESOURCE_TOMCAT_USER} "${HA_RSCTMP}/${TOMCAT_NAME}_tomcatstate/" ++if [ -z "$CATALINA_PID" ]; then ++ if [ "$__OCF_ACTION" = "start" ]; then ++ mkdir -p "${HA_RSCTMP}/${TOMCAT_NAME}_tomcatstate/" ++ if [ "${RESOURCE_TOMCAT_USER}" != "root" ]; then ++ chown ${RESOURCE_TOMCAT_USER} "${HA_RSCTMP}/${TOMCAT_NAME}_tomcatstate/" ++ fi + fi + CATALINA_PID="${HA_RSCTMP}/${TOMCAT_NAME}_tomcatstate/catalina.pid" + fi + +From b0da375699ebfa544e6e4a13eae554af3e7d65c9 Mon Sep 17 00:00:00 2001 +From: Oyvind Albrigtsen +Date: Fri, 28 Mar 2025 10:50:17 +0100 +Subject: [PATCH 2/2] tomcat: fix catalina_base and catalina_out parameter + defaults + +--- + heartbeat/tomcat | 6 +++--- + 1 file changed, 3 insertions(+), 3 deletions(-) + +diff --git a/heartbeat/tomcat b/heartbeat/tomcat +index 6d47980296..1e8f216384 100755 +--- a/heartbeat/tomcat ++++ b/heartbeat/tomcat +@@ -650,7 +650,6 @@ OCF_RESKEY_statusurl_default="http://127.0.0.1:8080" + OCF_RESKEY_max_stop_time_default="" + OCF_RESKEY_java_home_default="" + OCF_RESKEY_java_opts_default="" +-OCF_RESKEY_catalina_out_default="${OCF_RESKEY_catalina_base-${OCF_RESKEY_catalina_home}}/logs/catalina.out" + OCF_RESKEY_catalina_pid_default="" + OCF_RESKEY_tomcat_start_script_default="${TOMCAT_START_SCRIPT}" + OCF_RESKEY_tomcat_start_opts_default="" +@@ -670,7 +669,6 @@ OCF_RESKEY_logging_manager_default="" + : ${OCF_RESKEY_max_stop_time=${OCF_RESKEY_max_stop_time_default}} + : ${OCF_RESKEY_java_home=${OCF_RESKEY_java_home_default}} + : ${OCF_RESKEY_java_opts=${OCF_RESKEY_java_opts_default}} +-: ${OCF_RESKEY_catalina_out=${OCF_RESKEY_catalina_out_default}} + : ${OCF_RESKEY_catalina_pid=${OCF_RESKEY_catalina_pid_default}} + : ${OCF_RESKEY_tomcat_start_script=${OCF_RESKEY_tomcat_start_script_default}} + : ${OCF_RESKEY_tomcat_start_opts=${OCF_RESKEY_tomcat_start_opts_default}} +@@ -691,7 +689,9 @@ RESOURCE_STATUSURL="${OCF_RESKEY_statusurl}" + JAVA_HOME="${OCF_RESKEY_java_home}" + JAVA_OPTS="${OCF_RESKEY_java_opts}" + CATALINA_HOME="${OCF_RESKEY_catalina_home}" +-CATALINA_BASE="${OCF_RESKEY_catalina_base-${OCF_RESKEY_catalina_home}}" ++CATALINA_BASE="${OCF_RESKEY_catalina_base:-${OCF_RESKEY_catalina_home}}" ++OCF_RESKEY_catalina_out_default="${OCF_RESKEY_catalina_base:-${OCF_RESKEY_catalina_home}}/logs/catalina.out" ++: ${OCF_RESKEY_catalina_out=${OCF_RESKEY_catalina_out_default}} + CATALINA_OUT="${OCF_RESKEY_catalina_out}" + + CATALINA_PID=$OCF_RESKEY_catalina_pid diff --git a/SOURCES/RHEL-91257-Filesystem-add-support-for-aznfs.patch b/SOURCES/RHEL-91257-Filesystem-add-support-for-aznfs.patch new file mode 100644 index 0000000..65466e4 --- /dev/null +++ b/SOURCES/RHEL-91257-Filesystem-add-support-for-aznfs.patch @@ -0,0 +1,171 @@ +From 3bffa541f7bf66e143f14e51551fc91dfebec86c Mon Sep 17 00:00:00 2001 +From: Tobias Schug +Date: Mon, 28 Oct 2024 09:14:41 +0100 +Subject: [PATCH] Add azure aznfs filesystem support + +--- + heartbeat/Filesystem | 37 ++++++++++++++++++++----------------- + 1 file changed, 20 insertions(+), 17 deletions(-) + +diff --git a/heartbeat/Filesystem b/heartbeat/Filesystem +index 3405e2c26..b48bee142 100755 +--- a/heartbeat/Filesystem ++++ b/heartbeat/Filesystem +@@ -2,7 +2,7 @@ + # + # Support: users@clusterlabs.org + # License: GNU General Public License (GPL) +-# ++# + # Filesystem + # Description: Manages a Filesystem on a shared storage medium. + # Original Author: Eric Z. Ayers (eric.ayers@compgen.com) +@@ -142,7 +142,7 @@ meta_data() { + + + Resource script for Filesystem. It manages a Filesystem on a +-shared storage medium. ++shared storage medium. + + The standard monitor operation of depth 0 (also known as probe) + checks if the filesystem is mounted. If you want deeper tests, +@@ -260,7 +260,7 @@ currently accessing the mount directory. + "true" : Kill processes accessing mount point + "safe" : Kill processes accessing mount point using methods that + avoid functions that could potentially block during process +- detection ++ detection + "false" : Do not kill any processes. + + The 'safe' option uses shell logic to walk the /procs/ directory +@@ -373,7 +373,7 @@ determine_blockdevice() { + # Get the current real device name, if possible. + # (specified devname could be -L or -U...) + case "$FSTYPE" in +- nfs4|nfs|efs|smbfs|cifs|glusterfs|ceph|tmpfs|overlay|overlayfs|rozofs|zfs|cvfs|none|lustre) ++ nfs4|nfs|aznfs|efs|smbfs|cifs|glusterfs|ceph|tmpfs|overlay|overlayfs|rozofs|zfs|cvfs|none|lustre) + : ;; + *) + match_string="${TAB}${CANONICALIZED_MOUNTPOINT}${TAB}" +@@ -455,7 +455,7 @@ is_fsck_needed() { + no) false;; + ""|auto) + case "$FSTYPE" in +- ext4|ext4dev|ext3|reiserfs|reiser4|nss|xfs|jfs|vfat|fat|nfs4|nfs|efs|cifs|smbfs|ocfs2|gfs2|none|lustre|glusterfs|ceph|tmpfs|overlay|overlayfs|rozofs|zfs|cvfs) ++ ext4|ext4dev|ext3|reiserfs|reiser4|nss|xfs|jfs|vfat|fat|nfs4|nfs|aznfs|efs|cifs|smbfs|ocfs2|gfs2|none|lustre|glusterfs|ceph|tmpfs|overlay|overlayfs|rozofs|zfs|cvfs) + false;; + *) + true;; +@@ -478,7 +478,7 @@ fstype_supported() + fi + + if [ -z "$FSTYPE" -o "$FSTYPE" = none ]; then +- : No FSTYPE specified, rely on the system has the right file-system support already ++ : No FSTYPE specified, rely on the system has the right file-system support already + return $OCF_SUCCESS + fi + +@@ -487,6 +487,7 @@ fstype_supported() + case "$FSTYPE" in + fuse.*|glusterfs|rozofs) support="fuse";; + efs) check_binary "mount.efs"; support="nfs4";; ++ aznfs) check_binary "mount.aznfs"; support="nfs4";; + esac + + if [ "$support" != "$FSTYPE" ]; then +@@ -530,7 +531,7 @@ fstype_supported() + # node on the shared storage, and is not visible yet. Then try + # partprobe to refresh /dev/disk/by-{label,uuid}/* up to date. + # +-# DEVICE can be /dev/xxx, -U, -L ++# DEVICE can be /dev/xxx, -U, -L + # + trigger_udev_rules_if_needed() + { +@@ -545,12 +546,12 @@ trigger_udev_rules_if_needed() + fi + else + tmp="$(echo $DEVICE|awk '{$1=""; print substr($0,2)}')" +- case "$DEVICE" in +- -U*|--uuid*) +- tmp="/dev/disk/by-uuid/$tmp" ++ case "$DEVICE" in ++ -U*|--uuid*) ++ tmp="/dev/disk/by-uuid/$tmp" + ;; + -L*|--label*) +- tmp="/dev/disk/by-label/$tmp" ++ tmp="/dev/disk/by-label/$tmp" + ;; + *) + # bind mount? +@@ -595,7 +596,7 @@ Filesystem_start() + + fstype_supported || exit $OCF_ERR_INSTALLED + +- # Check the filesystem & auto repair. ++ # Check the filesystem & auto repair. + # NOTE: Some filesystem types don't need this step... Please modify + # accordingly + +@@ -697,7 +698,7 @@ signal_processes() { + local sig=$2 + local pids pid + # fuser returns a non-zero return code if none of the +- # specified files is accessed or in case of a fatal ++ # specified files is accessed or in case of a fatal + # error. + pids=$(get_pids "$dir") + if [ -z "$pids" ]; then +@@ -745,6 +746,7 @@ fs_stop_loop() { + try_umount "$force_arg" "$SUB" && return $OCF_SUCCESS + done + } ++ + fs_stop() { + local SUB="$1" timeout=$2 grace_time ret + grace_time=$((timeout/2)) +@@ -797,7 +799,7 @@ Filesystem_stop() + + # For networked filesystems, there's merit in trying -f: + case "$FSTYPE" in +- nfs4|nfs|efs|cifs|smbfs) umount_force="-f" ;; ++ nfs4|nfs|aznfs|efs|cifs|smbfs) umount_force="-f" ;; + esac + + # Umount all sub-filesystems mounted under $MOUNTPOINT/ too. +@@ -942,6 +944,7 @@ Filesystem_monitor_20() + fi + return $OCF_SUCCESS + } ++ + Filesystem_monitor() + { + Filesystem_status +@@ -1016,7 +1019,7 @@ set_blockdevice_var() { + + # these are definitely not block devices + case "$FSTYPE" in +- nfs4|nfs|efs|smbfs|cifs|none|glusterfs|ceph|tmpfs|overlay|overlayfs|rozofs|zfs|cvfs|lustre) return;; ++ nfs4|nfs|aznfs|efs|smbfs|cifs|none|glusterfs|ceph|tmpfs|overlay|overlayfs|rozofs|zfs|cvfs|lustre) return;; + esac + + if $(is_option "loop"); then +@@ -1098,7 +1101,7 @@ set_blockdevice_var + if [ -z "$OCF_RESKEY_directory" ]; then + if [ X$OP = "Xstart" -o $blockdevice = "no" ]; then + ocf_exit_reason "Please specify the directory" +- exit $OCF_ERR_CONFIGURED ++ exit $OCF_ERR_CONFIGURED + fi + else + MOUNTPOINT="$(echo "$OCF_RESKEY_directory" | sed 's/\/*$//')" +@@ -1166,7 +1169,7 @@ is_option "ro" && + CLUSTERSAFE=2 + + case "$FSTYPE" in +-nfs4|nfs|efs|smbfs|cifs|none|gfs2|glusterfs|ceph|ocfs2|overlay|overlayfs|tmpfs|cvfs|lustre) ++nfs4|nfs|aznfs|efs|smbfs|cifs|none|gfs2|glusterfs|ceph|ocfs2|overlay|overlayfs|tmpfs|cvfs|lustre) + CLUSTERSAFE=1 # this is kind of safe too + systemd_drop_in "99-Filesystem-remote" "After" "remote-fs.target" + ;; diff --git a/SOURCES/bz1904465-mysql-common-improve-error-message.patch b/SOURCES/bz1904465-mysql-common-improve-error-message.patch new file mode 100644 index 0000000..4a19fc4 --- /dev/null +++ b/SOURCES/bz1904465-mysql-common-improve-error-message.patch @@ -0,0 +1,68 @@ +From fcceb714085836de9db4493b527e94d85dd72626 Mon Sep 17 00:00:00 2001 +From: ut002970 +Date: Wed, 6 Sep 2023 15:27:05 +0800 +Subject: [PATCH 1/3] modify error message + +--- + heartbeat/mysql-common.sh | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/mysql-common.sh b/heartbeat/mysql-common.sh +index 8104019b03..a93acc4c60 100755 +--- a/heartbeat/mysql-common.sh ++++ b/heartbeat/mysql-common.sh +@@ -254,7 +254,7 @@ mysql_common_start() + while [ $start_wait = 1 ]; do + if ! ps $pid > /dev/null 2>&1; then + wait $pid +- ocf_exit_reason "MySQL server failed to start (pid=$pid) (rc=$?), please check your installation" ++ ocf_exit_reason "MySQL server failed to start (pid=$pid) (rc=$?), please check your installation, log message you can check $OCF_RESKEY_log" + return $OCF_ERR_GENERIC + fi + mysql_common_status info + +From 8f9b344cd5b3cb96ea0f94b7ab0306da2234ac00 Mon Sep 17 00:00:00 2001 +From: ut002970 +Date: Wed, 6 Sep 2023 15:56:24 +0800 +Subject: [PATCH 2/3] modify error message + +--- + heartbeat/mysql-common.sh | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/mysql-common.sh b/heartbeat/mysql-common.sh +index a93acc4c60..d5b2286737 100755 +--- a/heartbeat/mysql-common.sh ++++ b/heartbeat/mysql-common.sh +@@ -254,7 +254,7 @@ mysql_common_start() + while [ $start_wait = 1 ]; do + if ! ps $pid > /dev/null 2>&1; then + wait $pid +- ocf_exit_reason "MySQL server failed to start (pid=$pid) (rc=$?), please check your installation, log message you can check $OCF_RESKEY_log" ++ ocf_exit_reason "MySQL server failed to start (pid=$pid) (rc=$?), Check $OCF_RESKEY_log for details" + return $OCF_ERR_GENERIC + fi + mysql_common_status info + +From a292b3c552bf3f2beea5f73e0d171546c0a1273c Mon Sep 17 00:00:00 2001 +From: ut002970 +Date: Wed, 6 Sep 2023 16:10:48 +0800 +Subject: [PATCH 3/3] modify error message + +--- + heartbeat/mysql-common.sh | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/heartbeat/mysql-common.sh b/heartbeat/mysql-common.sh +index d5b2286737..d6b4e3cdf4 100755 +--- a/heartbeat/mysql-common.sh ++++ b/heartbeat/mysql-common.sh +@@ -254,7 +254,7 @@ mysql_common_start() + while [ $start_wait = 1 ]; do + if ! ps $pid > /dev/null 2>&1; then + wait $pid +- ocf_exit_reason "MySQL server failed to start (pid=$pid) (rc=$?), Check $OCF_RESKEY_log for details" ++ ocf_exit_reason "MySQL server failed to start (pid=$pid) (rc=$?). Check $OCF_RESKEY_log for details" + return $OCF_ERR_GENERIC + fi + mysql_common_status info diff --git a/SOURCES/bz2182415-azure-events-1-fix-no-transition-summary.patch b/SOURCES/bz2182415-azure-events-1-fix-no-transition-summary.patch deleted file mode 100644 index ed2958e..0000000 --- a/SOURCES/bz2182415-azure-events-1-fix-no-transition-summary.patch +++ /dev/null @@ -1,54 +0,0 @@ -From 81bb58b05d2ddabd17fe31af39f0e857e61db3c9 Mon Sep 17 00:00:00 2001 -From: Oyvind Albrigtsen -Date: Tue, 28 Mar 2023 16:53:45 +0200 -Subject: [PATCH] azure-events*: fix for no "Transition Summary" for Pacemaker - 2.1+ - ---- - heartbeat/azure-events-az.in | 8 ++++---- - heartbeat/azure-events.in | 6 +++--- - 2 files changed, 7 insertions(+), 7 deletions(-) - -diff --git a/heartbeat/azure-events-az.in b/heartbeat/azure-events-az.in -index 59d0953061..67c02c6422 100644 ---- a/heartbeat/azure-events-az.in -+++ b/heartbeat/azure-events-az.in -@@ -311,10 +311,10 @@ class clusterHelper: - summary = clusterHelper._exec("crm_simulate", "-Ls") - if not summary: - ocf.logger.warning("transitionSummary: could not load transition summary") -- return False -+ return "" - if summary.find("Transition Summary:") < 0: -- ocf.logger.warning("transitionSummary: received unexpected transition summary: %s" % summary) -- return False -+ ocf.logger.debug("transitionSummary: no transactions: %s" % summary) -+ return "" - summary = summary.split("Transition Summary:")[1] - ret = summary.split("\n").pop(0) - -@@ -768,4 +768,4 @@ def main(): - agent.run() - - if __name__ == '__main__': -- main() -\ No newline at end of file -+ main() -diff --git a/heartbeat/azure-events.in b/heartbeat/azure-events.in -index 66e129060a..5ad658df93 100644 ---- a/heartbeat/azure-events.in -+++ b/heartbeat/azure-events.in -@@ -310,10 +310,10 @@ class clusterHelper: - summary = clusterHelper._exec("crm_simulate", "-Ls") - if not summary: - ocf.logger.warning("transitionSummary: could not load transition summary") -- return False -+ return "" - if summary.find("Transition Summary:") < 0: -- ocf.logger.warning("transitionSummary: received unexpected transition summary: %s" % summary) -- return False -+ ocf.logger.debug("transitionSummary: no transactions: %s" % summary) -+ return "" - summary = summary.split("Transition Summary:")[1] - ret = summary.split("\n").pop(0) - diff --git a/SOURCES/bz2182415-azure-events-2-improve-logic.patch b/SOURCES/bz2182415-azure-events-2-improve-logic.patch deleted file mode 100644 index 1b5aa9d..0000000 --- a/SOURCES/bz2182415-azure-events-2-improve-logic.patch +++ /dev/null @@ -1,77 +0,0 @@ -From ff53e5c8d6867e580506d132fba6fcf6aa46b804 Mon Sep 17 00:00:00 2001 -From: Peter Varkoly -Date: Sat, 29 Apr 2023 08:09:11 +0200 -Subject: [PATCH] Use -LS instead of -Ls as parameter to get the Transition - Summary - ---- - heartbeat/azure-events-az.in | 9 +++++---- - heartbeat/azure-events.in | 9 +++++---- - 2 files changed, 10 insertions(+), 8 deletions(-) - -diff --git a/heartbeat/azure-events-az.in b/heartbeat/azure-events-az.in -index 67c02c642..46d4d1f3d 100644 ---- a/heartbeat/azure-events-az.in -+++ b/heartbeat/azure-events-az.in -@@ -298,7 +298,7 @@ class clusterHelper: - Get the current Pacemaker transition summary (used to check if all resources are stopped when putting a node standby) - """ - # Is a global crm_simulate "too much"? Or would it be sufficient it there are no planned transitions for a particular node? -- # # crm_simulate -Ls -+ # # crm_simulate -LS - # Transition Summary: - # * Promote rsc_SAPHana_HN1_HDB03:0 (Slave -> Master hsr3-db1) - # * Stop rsc_SAPHana_HN1_HDB03:1 (hsr3-db0) -@@ -308,15 +308,16 @@ class clusterHelper: - # Transition Summary: - ocf.logger.debug("transitionSummary: begin") - -- summary = clusterHelper._exec("crm_simulate", "-Ls") -+ summary = clusterHelper._exec("crm_simulate", "-LS") - if not summary: - ocf.logger.warning("transitionSummary: could not load transition summary") - return "" - if summary.find("Transition Summary:") < 0: - ocf.logger.debug("transitionSummary: no transactions: %s" % summary) - return "" -- summary = summary.split("Transition Summary:")[1] -- ret = summary.split("\n").pop(0) -+ j=summary.find('Transition Summary:') + len('Transition Summary:') -+ l=summary.lower().find('executing cluster transition:') -+ ret = list(filter(str.strip, summary[j:l].split("\n"))) - - ocf.logger.debug("transitionSummary: finished; return = %s" % str(ret)) - return ret -diff --git a/heartbeat/azure-events.in b/heartbeat/azure-events.in -index 5ad658df9..90acaba62 100644 ---- a/heartbeat/azure-events.in -+++ b/heartbeat/azure-events.in -@@ -297,7 +297,7 @@ class clusterHelper: - Get the current Pacemaker transition summary (used to check if all resources are stopped when putting a node standby) - """ - # Is a global crm_simulate "too much"? Or would it be sufficient it there are no planned transitions for a particular node? -- # # crm_simulate -Ls -+ # # crm_simulate -LS - # Transition Summary: - # * Promote rsc_SAPHana_HN1_HDB03:0 (Slave -> Master hsr3-db1) - # * Stop rsc_SAPHana_HN1_HDB03:1 (hsr3-db0) -@@ -307,15 +307,16 @@ class clusterHelper: - # Transition Summary: - ocf.logger.debug("transitionSummary: begin") - -- summary = clusterHelper._exec("crm_simulate", "-Ls") -+ summary = clusterHelper._exec("crm_simulate", "-LS") - if not summary: - ocf.logger.warning("transitionSummary: could not load transition summary") - return "" - if summary.find("Transition Summary:") < 0: - ocf.logger.debug("transitionSummary: no transactions: %s" % summary) - return "" -- summary = summary.split("Transition Summary:")[1] -- ret = summary.split("\n").pop(0) -+ j=summary.find('Transition Summary:') + len('Transition Summary:') -+ l=summary.lower().find('executing cluster transition:') -+ ret = list(filter(str.strip, summary[j:l].split("\n"))) - - ocf.logger.debug("transitionSummary: finished; return = %s" % str(ret)) - return ret diff --git a/SOURCES/findif-dont-use-table-parameter-as-it-returns-no-netmask.patch b/SOURCES/findif-dont-use-table-parameter-as-it-returns-no-netmask.patch deleted file mode 100644 index ef5d8d5..0000000 --- a/SOURCES/findif-dont-use-table-parameter-as-it-returns-no-netmask.patch +++ /dev/null @@ -1,79 +0,0 @@ -From cf2fd2a9cf06dc2e915f2fb5dbcc5e09e907a6df Mon Sep 17 00:00:00 2001 -From: Oyvind Albrigtsen -Date: Thu, 5 Oct 2023 11:53:18 +0200 -Subject: [PATCH] findif.sh: dont use table parameter as it returns no netmask - (tested with main/local/custom tables) - ---- - heartbeat/IPaddr2 | 12 ------------ - heartbeat/findif.sh | 8 ++++---- - 2 files changed, 4 insertions(+), 16 deletions(-) - -diff --git a/heartbeat/IPaddr2 b/heartbeat/IPaddr2 -index e8384c5866..97a7431a24 100755 ---- a/heartbeat/IPaddr2 -+++ b/heartbeat/IPaddr2 -@@ -73,7 +73,6 @@ OCF_RESKEY_ip_default="" - OCF_RESKEY_cidr_netmask_default="" - OCF_RESKEY_broadcast_default="" - OCF_RESKEY_iflabel_default="" --OCF_RESKEY_table_default="" - OCF_RESKEY_cidr_netmask_default="" - OCF_RESKEY_lvs_support_default=false - OCF_RESKEY_lvs_ipv6_addrlabel_default=false -@@ -98,7 +97,6 @@ OCF_RESKEY_network_namespace_default="" - : ${OCF_RESKEY_cidr_netmask=${OCF_RESKEY_cidr_netmask_default}} - : ${OCF_RESKEY_broadcast=${OCF_RESKEY_broadcast_default}} - : ${OCF_RESKEY_iflabel=${OCF_RESKEY_iflabel_default}} --: ${OCF_RESKEY_table=${OCF_RESKEY_table_default}} - : ${OCF_RESKEY_lvs_support=${OCF_RESKEY_lvs_support_default}} - : ${OCF_RESKEY_lvs_ipv6_addrlabel=${OCF_RESKEY_lvs_ipv6_addrlabel_default}} - : ${OCF_RESKEY_lvs_ipv6_addrlabel_value=${OCF_RESKEY_lvs_ipv6_addrlabel_value_default}} -@@ -241,16 +239,6 @@ If a label is specified in nic name, this parameter has no effect. - - - -- -- --Table to use to lookup which interface to use for the IP. -- --This can be used for policy based routing. See man ip-rule(8). -- --Table -- -- -- - - - Enable support for LVS Direct Routing configurations. In case a IP -diff --git a/heartbeat/findif.sh b/heartbeat/findif.sh -index 6c04c98c19..5f1c19ec3c 100644 ---- a/heartbeat/findif.sh -+++ b/heartbeat/findif.sh -@@ -32,7 +32,7 @@ prefixcheck() { - getnetworkinfo() - { - local line netinfo -- ip -o -f inet route list match $OCF_RESKEY_ip table "${OCF_RESKEY_table:=main}" scope host | (while read line; -+ ip -o -f inet route list match $OCF_RESKEY_ip scope host | (while read line; - do - netinfo=`echo $line | awk '{print $2}'` - case $netinfo in -@@ -210,14 +210,14 @@ findif() - fi - findif_check_params $family || return $? - -- if [ -n "$netmask" ] ; then -+ if [ -n "$netmask" ]; then - match=$match/$netmask - fi - if [ -n "$nic" ] ; then - # NIC supports more than two. -- set -- $(ip -o -f $family route list match $match $scope table "${OCF_RESKEY_table:=main}" | grep "dev $nic " | awk 'BEGIN{best=0} /\// { mask=$1; sub(".*/", "", mask); if( int(mask)>=best ) { best=int(mask); best_ln=$0; } } END{print best_ln}') -+ set -- $(ip -o -f $family route list match $match $scope | grep "dev $nic " | awk 'BEGIN{best=0} /\// { mask=$1; sub(".*/", "", mask); if( int(mask)>=best ) { best=int(mask); best_ln=$0; } } END{print best_ln}') - else -- set -- $(ip -o -f $family route list match $match $scope table "${OCF_RESKEY_table:=main}" | awk 'BEGIN{best=0} /\// { mask=$1; sub(".*/", "", mask); if( int(mask)>=best ) { best=int(mask); best_ln=$0; } } END{print best_ln}') -+ set -- $(ip -o -f $family route list match $match $scope | awk 'BEGIN{best=0} /\// { mask=$1; sub(".*/", "", mask); if( int(mask)>=best ) { best=int(mask); best_ln=$0; } } END{print best_ln}') - fi - if [ $# = 0 ] ; then - case $OCF_RESKEY_ip in diff --git a/SOURCES/python3-syntax-fixes.patch b/SOURCES/python3-syntax-fixes.patch index a34e312..c669dd5 100644 --- a/SOURCES/python3-syntax-fixes.patch +++ b/SOURCES/python3-syntax-fixes.patch @@ -590,116 +590,3 @@ diff -uNr a/bundled/aliyun/colorama/demos/demo07.py b/bundled/aliyun/colorama/de if __name__ == '__main__': -diff -uNr a/bundled/aliyun/pycryptodome/Doc/conf.py b/bundled/aliyun/pycryptodome/Doc/conf.py ---- a/bundled/aliyun/pycryptodome/Doc/conf.py 2018-07-10 21:32:46.000000000 +0200 -+++ b/bundled/aliyun/pycryptodome/Doc/conf.py 2018-10-08 12:08:11.122188094 +0200 -@@ -15,7 +15,7 @@ - - # Modules to document with autodoc are in another directory - sys.path.insert(0, os.path.abspath('../lib')) --print sys.path -+print(sys.path) - - # Mock existance of native modules - from Crypto.Util import _raw_api -diff -uNr a/bundled/aliyun/pycryptodome/lib/Crypto/Math/Primality.py b/bundled/aliyun/pycryptodome/lib/Crypto/Math/Primality.py ---- a/bundled/aliyun/pycryptodome/lib/Crypto/Math/Primality.py 2018-07-10 21:32:46.000000000 +0200 -+++ b/bundled/aliyun/pycryptodome/lib/Crypto/Math/Primality.py 2018-10-08 12:08:11.123188075 +0200 -@@ -302,7 +302,7 @@ - randfunc = kwargs.pop("randfunc", None) - prime_filter = kwargs.pop("prime_filter", lambda x: True) - if kwargs: -- print "Unknown parameters:", kwargs.keys() -+ print("Unknown parameters:", kwargs.keys()) - - if exact_bits is None: - raise ValueError("Missing exact_bits parameter") -@@ -341,7 +341,7 @@ - exact_bits = kwargs.pop("exact_bits", None) - randfunc = kwargs.pop("randfunc", None) - if kwargs: -- print "Unknown parameters:", kwargs.keys() -+ print("Unknown parameters:", kwargs.keys()) - - if randfunc is None: - randfunc = Random.new().read -diff -uNr a/bundled/aliyun/pycryptodome/lib/Crypto/PublicKey/ECC.py b/bundled/aliyun/pycryptodome/lib/Crypto/PublicKey/ECC.py ---- a/bundled/aliyun/pycryptodome/lib/Crypto/PublicKey/ECC.py 2018-07-10 21:32:46.000000000 +0200 -+++ b/bundled/aliyun/pycryptodome/lib/Crypto/PublicKey/ECC.py 2018-10-08 12:08:11.124188057 +0200 -@@ -912,4 +912,4 @@ - count = 30 - for x in xrange(count): - _ = point * d -- print (time.time() - start) / count * 1000, "ms" -+ print((time.time() - start) / count * 1000, "ms") -diff -uNr a/bundled/aliyun/pycryptodome/lib/Crypto/SelfTest/Cipher/test_AES.py b/bundled/aliyun/pycryptodome/lib/Crypto/SelfTest/Cipher/test_AES.py ---- a/bundled/aliyun/pycryptodome/lib/Crypto/SelfTest/Cipher/test_AES.py 2018-07-10 21:32:46.000000000 +0200 -+++ b/bundled/aliyun/pycryptodome/lib/Crypto/SelfTest/Cipher/test_AES.py 2018-10-08 12:08:11.124188057 +0200 -@@ -1276,7 +1276,7 @@ - tests += make_block_tests(AES, "AESNI", test_data, {'use_aesni': True}) - tests += [ TestMultipleBlocks(True) ] - else: -- print "Skipping AESNI tests" -+ print("Skipping AESNI tests") - return tests - - if __name__ == '__main__': -diff -uNr a/bundled/aliyun/pycryptodome/lib/Crypto/SelfTest/Cipher/test_GCM.py b/bundled/aliyun/pycryptodome/lib/Crypto/SelfTest/Cipher/test_GCM.py ---- a/bundled/aliyun/pycryptodome/lib/Crypto/SelfTest/Cipher/test_GCM.py 2018-07-10 21:32:46.000000000 +0200 -+++ b/bundled/aliyun/pycryptodome/lib/Crypto/SelfTest/Cipher/test_GCM.py 2018-10-08 12:08:11.125188038 +0200 -@@ -894,7 +894,7 @@ - if config.get('slow_tests'): - tests += list_test_cases(NISTTestVectorsGCM_no_clmul) - else: -- print "Skipping test of PCLMULDQD in AES GCM" -+ print("Skipping test of PCLMULDQD in AES GCM") - - return tests - -diff -uNr a/bundled/aliyun/pycryptodome/lib/Crypto/SelfTest/Cipher/test_pkcs1_15.py b/bundled/aliyun/pycryptodome/lib/Crypto/SelfTest/Cipher/test_pkcs1_15.py ---- a/bundled/aliyun/pycryptodome/lib/Crypto/SelfTest/Cipher/test_pkcs1_15.py 2018-07-10 21:32:46.000000000 +0200 -+++ b/bundled/aliyun/pycryptodome/lib/Crypto/SelfTest/Cipher/test_pkcs1_15.py 2018-10-08 12:08:11.125188038 +0200 -@@ -39,7 +39,7 @@ - """Convert a text string with bytes in hex form to a byte string""" - clean = b(rws(t)) - if len(clean)%2 == 1: -- print clean -+ print(clean) - raise ValueError("Even number of characters expected") - return a2b_hex(clean) - -diff -uNr a/bundled/aliyun/pycryptodome/lib/Crypto/SelfTest/__main__.py b/bundled/aliyun/pycryptodome/lib/Crypto/SelfTest/__main__.py ---- a/bundled/aliyun/pycryptodome/lib/Crypto/SelfTest/__main__.py 2018-07-10 21:32:46.000000000 +0200 -+++ b/bundled/aliyun/pycryptodome/lib/Crypto/SelfTest/__main__.py 2018-10-08 12:08:11.126188020 +0200 -@@ -25,11 +25,11 @@ - - slow_tests = not "--skip-slow-tests" in sys.argv - if not slow_tests: -- print "Skipping slow tests" -+ print("Skipping slow tests") - - wycheproof_warnings = "--wycheproof-warnings" in sys.argv - if wycheproof_warnings: -- print "Printing Wycheproof warnings" -+ print("Printing Wycheproof warnings") - - config = {'slow_tests' : slow_tests, 'wycheproof_warnings' : wycheproof_warnings } - SelfTest.run(stream=sys.stdout, verbosity=1, config=config) -diff -uNr a/bundled/aliyun/pycryptodome/lib/Crypto/Util/RFC1751.py b/bundled/aliyun/pycryptodome/lib/Crypto/Util/RFC1751.py ---- a/bundled/aliyun/pycryptodome/lib/Crypto/Util/RFC1751.py 2018-07-10 21:32:46.000000000 +0200 -+++ b/bundled/aliyun/pycryptodome/lib/Crypto/Util/RFC1751.py 2018-10-08 12:08:11.126188020 +0200 -@@ -369,13 +369,13 @@ - ] - - for key, words in data: -- print 'Trying key', key -+ print('Trying key', key) - key=binascii.a2b_hex(key) - w2=key_to_english(key) - if w2!=words: -- print 'key_to_english fails on key', repr(key), ', producing', str(w2) -+ print('key_to_english fails on key', repr(key), ', producing', str(w2)) - k2=english_to_key(words) - if k2!=key: -- print 'english_to_key fails on key', repr(key), ', producing', repr(k2) -+ print('english_to_key fails on key', repr(key), ', producing', repr(k2)) diff --git a/SPECS/resource-agents.spec b/SPECS/resource-agents.spec index 2b85ff5..fbfe65a 100644 --- a/SPECS/resource-agents.spec +++ b/SPECS/resource-agents.spec @@ -43,7 +43,7 @@ %global colorama_dir %{bundled_lib_dir}/aliyun/%{colorama} # python-pycryptodome bundle %global pycryptodome pycryptodome -%global pycryptodome_version 3.6.4 +%global pycryptodome_version 3.20.0 %global pycryptodome_dir %{bundled_lib_dir}/aliyun/%{pycryptodome} # python-aliyun-sdk-core bundle %global aliyunsdkcore aliyun-python-sdk-core @@ -61,6 +61,10 @@ %global aliyuncli aliyun-cli %global aliyuncli_version 2.1.10 %global aliyuncli_dir %{bundled_lib_dir}/aliyun/%{aliyuncli} +## fix CVEs +# urllib3 bundle +%global urllib3 urllib3 +%global urllib3_version 1.26.18 # determine the ras-set to process based on configure invokation %bcond_with rgmanager @@ -69,7 +73,7 @@ Name: resource-agents Summary: Open Source HA Reusable Cluster Resource Scripts Version: 4.9.0 -Release: 48%{?rcver:%{rcver}}%{?numcomm:.%{numcomm}}%{?alphatag:.%{alphatag}}%{?dirty:.%{dirty}}%{?dist}.alma.1 +Release: 54%{?rcver:%{rcver}}%{?numcomm:.%{numcomm}}%{?alphatag:.%{alphatag}}%{?dirty:.%{dirty}}%{?dist}.33.alma.1 License: GPLv2+ and LGPLv2+ URL: https://github.com/ClusterLabs/resource-agents %if 0%{?fedora} || 0%{?centos_version} || 0%{?rhel} @@ -88,6 +92,7 @@ Source7: %{aliyunsdkcore}-%{aliyunsdkcore_version}.tar.gz Source8: %{aliyunsdkecs}-%{aliyunsdkecs_version}.tar.gz Source9: %{aliyunsdkvpc}-%{aliyunsdkvpc_version}.tar.gz Source10: %{aliyuncli}-%{aliyuncli_version}.tar.gz +Source11: %{urllib3}-%{urllib3_version}.tar.gz Patch0: nova-compute-wait-NovaEvacuate.patch Patch1: bz1872754-pgsqlms-new-ra.patch Patch2: bz1995178-storage-mon-fix-typo.patch @@ -148,10 +153,38 @@ Patch56: bz2040110-IPaddr2-IPsrcaddr-2-fix-table-parameter.patch Patch57: bz2189243-Filesystem-1-improve-stop-action.patch Patch58: bz2189243-Filesystem-2-fix-incorrect-parameter-types.patch Patch59: bz2189243-Filesystem-3-fix-signal_delay-default-value.patch - -# Patches were taken from: -# https://github.com/ClusterLabs/resource-agents/commit/cf2fd2a9cf06dc2e915f2fb5dbcc5e09e907a6df -Patch60: findif-dont-use-table-parameter-as-it-returns-no-netmask.patch +Patch60: bz1904465-mysql-common-improve-error-message.patch +Patch61: RHEL-15302-1-exportfs-make-fsid-optional.patch +Patch62: RHEL-15302-2-ocft-exportfs-remove-fsid-required-test.patch +Patch63: RHEL-15305-1-findif.sh-fix-loopback-handling.patch +Patch64: RHEL-16248-aws-vpc-move-ip-aws-vpc-route53-awseip-awsvip-auth_type-role.patch +Patch65: RHEL-17083-findif-EOS-fix.patch +Patch66: RHEL-15305-2-findif.sh-dont-use-table-parameter.patch +Patch67: RHEL-34137-aws-agents-use-curl_retry.patch +Patch68: RHEL-32828-db2-fix-OCF_SUCESS-typo.patch +Patch69: RHEL-61138-nfsserver-also-stop-rpc-statd-for-nfsv4_only.patch +Patch70: RHEL-69297-1-Filesystem-dont-kill-unrelated-processes.patch +Patch71: RHEL-69297-2-Filesystem-update-bsd-logic.patch +Patch72: RHEL-72956-1-openstack-cinder-volume-wait-for-volume-to-be-available.patch +Patch73: RHEL-72956-2-openstack-cinder-volume-fix-detach-not-working-during-start-action.patch +Patch74: RHEL-79823-portblock-fix-version-detection.patch +Patch75: RHEL-81960-1-aws-agents-reuse-imds-token-until-it-expires.patch +Patch76: RHEL-81960-2-aws-agents-reuse-imds-token-improvements.patch +Patch77: RHEL-85048-tomcat-fix-CATALINA_PID-not-set-and-parameter-defaults.patch +Patch78: RHEL-91257-Filesystem-add-support-for-aznfs.patch +Patch79: RHEL-102731-ocf-shellfuncs-remove-extra-sleep-from-curl_retry.patch +Patch80: RHEL-115783-RHEL-115781-db2-add-skip_basic_sql_health_check-and-monitor-parameters.patch +Patch81: RHEL-118625-db2-use-reintegration-flag-to-avoid-race-condition-on-cluster-reintegration.patch +Patch82: RHEL-116150-1-ocf-shellfuncs-add-ocf_promotion_score.patch +Patch83: RHEL-116150-2-portblock-add-promotable-support.patch +Patch84: RHEL-116150-3-portblock-fixes-add-method-and-status_check-parameters.patch +Patch85: RHEL-124815-db2-fix-variable-name.patch +Patch86: RHEL-102979-1-nfsserver-support-non-clustered-kerberized-mounts.patch +Patch87: RHEL-102979-2-nfsserver-fix-error-message.patch +Patch88: RHEL-152316-portblock-check-inverse-action.patch +Patch89: RHEL-153157-db2-set-reintegration-when-promotion-is-successful.patch +Patch90: RHEL-166181-1-db2-fix-bashism.patch +Patch91: RHEL-166181-2-db2-do-not-use-db2stop-to-avoid-divergence-in-the-log.patch # bundle patches Patch1000: 7-gcp-bundled.patch @@ -164,6 +197,17 @@ Patch1006: python3-syntax-fixes.patch Patch1007: aliyuncli-python3-fixes.patch Patch1008: bz1935422-python-pygments-fix-CVE-2021-20270.patch Patch1009: bz1943464-python-pygments-fix-CVE-2021-27291.patch +Patch1010: RHEL-44923-aliyun-gcp-fix-bundled-urllib3-CVE-2024-37891.patch +Patch1011: RHEL-104761-aliyun-gcp-fix-bundled-requests-CVE-2024-47081.patch +Patch1012: RHEL-50360-setuptools-fix-CVE-2024-6345.patch +Patch1013: RHEL-136031-fix-bundled-urllib3-CVE-2025-66418.patch +Patch1014: RHEL-139760-fix-bundled-urllib3-CVE-2025-66471.patch +Patch1015: RHEL-140787-RHEL-146289-fix-bundled-urllib3-CVE-2026-21441.patch +Patch1016: RHEL-142448-fix-bundled-pyasn1-CVE-2026-23490.patch +Patch1017: RHEL-157190-fix-bundled-pyasn1-CVE-2026-30922.patch + +# AlmaLinux Patch +Patch2000: 1000-ocf-distro-add-AlmaLinux-to-RHEL-based-distro-detection.patch Obsoletes: heartbeat-resources <= %{version} Provides: heartbeat-resources = %{version} @@ -258,6 +302,8 @@ Provides: bundled(python-aliyun-sdk-ecs) = %{aliyunsdkecs_version} Provides: bundled(python-aliyun-sdk-vpc) = %{aliyunsdkvpc_version} # aliyuncli bundle Provides: bundled(aliyuncli) = %{aliyuncli_version} +# urllib3 bundle +Provides: bundled(python-urllib3) = %{urllib3_version} %description aliyun Alibaba Cloud (Aliyun) resource agents allows Alibaba Cloud @@ -297,7 +343,7 @@ Provides: bundled(python-pyparsing) = 2.1.10 Provides: bundled(python-requests) = 2.10.0 Provides: bundled(python-six) = 1.11.0 Provides: bundled(python-uritemplate) = 3.0.0 -Provides: bundled(python-urllib3) = 1.15.1 +Provides: bundled(python-urllib3) = %{urllib3_version} Provides: bundled(python-websocket) = 0.47.0 Provides: bundled(python-yaml) = 3.12 # python-pyroute2 bundle @@ -331,67 +377,101 @@ databases to be managed in a cluster environment. exit 1 %endif %setup -q -n %{upstream_prefix}-%{upstream_version} -%patch0 -p1 -%patch1 -p1 -%patch2 -p1 -%patch3 -p1 -%patch4 -p1 -%patch5 -p1 -%patch6 -p1 -%patch7 -p1 -%patch8 -p1 -%patch9 -p1 -%patch10 -p1 -%patch11 -p1 -%patch12 -p1 -%patch13 -p1 -%patch14 -p1 -%patch15 -p1 -%patch16 -p1 -%patch17 -p1 -%patch18 -p1 -%patch19 -p1 -%patch20 -p1 -%patch21 -p1 -%patch22 -p1 -%patch23 -p1 -%patch24 -p1 -%patch25 -p1 -%patch26 -p1 -%patch27 -p1 -%patch28 -p1 -%patch29 -p1 -%patch30 -p1 -%patch31 -p1 -%patch32 -p1 -%patch33 -p1 -%patch34 -p1 -%patch35 -p1 -%patch36 -p1 -%patch37 -p1 -%patch38 -p1 -%patch39 -p1 -%patch40 -p1 -%patch41 -p1 -%patch42 -p1 -%patch43 -p1 -%patch44 -p1 -%patch45 -p1 -%patch46 -p1 -%patch47 -p1 -%patch48 -p1 -%patch49 -p1 -%patch50 -p1 -%patch51 -p1 -%patch52 -p1 -%patch53 -p1 -%patch54 -p1 -%patch55 -p1 -%patch56 -p1 -%patch57 -p1 -%patch58 -p1 -%patch59 -p1 -%patch60 -p1 + +# Applying AlmaLinux Patch +%patch -P 2000 -p1 -b .1000-ocf-distro-add-AlmaLinux-to-RHEL-based-distro-detection +%patch -p1 -P 0 +%patch -p1 -P 1 +%patch -p1 -P 2 +%patch -p1 -P 3 +%patch -p1 -P 4 +%patch -p1 -P 5 +%patch -p1 -P 6 +%patch -p1 -P 7 +%patch -p1 -P 8 +%patch -p1 -P 9 +%patch -p1 -P 10 +%patch -p1 -P 11 +%patch -p1 -P 12 +%patch -p1 -P 13 +%patch -p1 -P 14 +%patch -p1 -P 15 +%patch -p1 -P 16 +%patch -p1 -P 17 +%patch -p1 -P 18 +%patch -p1 -P 19 +%patch -p1 -P 20 +%patch -p1 -P 21 +%patch -p1 -P 22 +%patch -p1 -P 23 +%patch -p1 -P 24 +%patch -p1 -P 25 +%patch -p1 -P 26 +%patch -p1 -P 27 +%patch -p1 -P 28 +%patch -p1 -P 29 +%patch -p1 -P 30 +%patch -p1 -P 31 +%patch -p1 -P 32 +%patch -p1 -P 33 +%patch -p1 -P 34 +%patch -p1 -P 35 +%patch -p1 -P 36 +%patch -p1 -P 37 +%patch -p1 -P 38 +%patch -p1 -P 39 +%patch -p1 -P 40 +%patch -p1 -P 41 +%patch -p1 -P 42 +%patch -p1 -P 43 +%patch -p1 -P 44 +%patch -p1 -P 45 +%patch -p1 -P 46 +%patch -p1 -P 47 +%patch -p1 -P 48 +%patch -p1 -P 49 +%patch -p1 -P 50 +%patch -p1 -P 51 +%patch -p1 -P 52 +%patch -p1 -P 53 +%patch -p1 -P 54 +%patch -p1 -P 55 +%patch -p1 -P 56 +%patch -p1 -P 57 +%patch -p1 -P 58 +%patch -p1 -P 59 +%patch -p1 -P 60 +%patch -p1 -P 61 +%patch -p1 -P 62 +%patch -p1 -P 63 +%patch -p1 -P 64 +%patch -p1 -P 65 +%patch -p1 -P 66 +%patch -p1 -P 67 -F1 +%patch -p1 -P 68 +%patch -p1 -P 69 +%patch -p1 -P 70 +%patch -p1 -P 71 +%patch -p1 -P 72 +%patch -p1 -P 73 +%patch -p1 -P 74 +%patch -p1 -P 75 +%patch -p1 -P 76 +%patch -p1 -P 77 +%patch -p1 -P 78 -F2 +%patch -p1 -P 79 +%patch -p1 -P 80 +%patch -p1 -P 81 -F2 +%patch -p1 -P 82 +%patch -p1 -P 83 +%patch -p1 -P 84 +%patch -p1 -P 85 +%patch -p1 -P 86 +%patch -p1 -P 87 +%patch -p1 -P 88 +%patch -p1 -P 89 +%patch -p1 -P 90 +%patch -p1 -P 91 chmod 755 heartbeat/nova-compute-wait chmod 755 heartbeat/NovaEvacuate @@ -405,15 +485,15 @@ mkdir -p %{bundled_lib_dir}/aliyun %ifarch x86_64 tar -xzf %SOURCE1 -C %{bundled_lib_dir}/gcp # gcp*: append bundled-directory to search path, gcloud-ra -%patch1000 -p1 +%patch -p1 -P 1000 # replace python-rsa with python-cryptography -%patch1001 -p1 +%patch -p1 -P 1001 # gcloud support info -%patch1002 -p1 +%patch -p1 -P 1002 # configure: skip bundled gcp lib checks -%patch1003 -p1 -F1 +%patch -p1 -P 1003 -F1 # gcloud remove python 2 detection -%patch1004 -p1 +%patch -p1 -P 1004 # rename gcloud mv %{googlecloudsdk_dir}/bin/gcloud %{googlecloudsdk_dir}/bin/gcloud-ra # keep googleapiclient @@ -520,16 +600,16 @@ mv %{bundled_lib_dir}/aliyun/%{aliyuncli}-%{aliyuncli_version} %{aliyuncli_dir} cp %{aliyuncli_dir}/README.rst %{aliyuncli}_README.rst cp %{aliyuncli_dir}/LICENSE %{aliyuncli}_LICENSE # aliyun*: use bundled libraries -%patch1005 -p1 +%patch -p1 -P 1005 # aliyun Python 3 fixes -%patch1006 -p1 -%patch1007 -p1 +%patch -p1 -P 1006 +%patch -p1 -P 1007 # fix CVE's in python-pygments pushd %{googlecloudsdk_dir}/lib/third_party -%patch1008 -p1 -F2 -%patch1009 -p1 -F2 +%patch -p1 -P 1008 -F2 +%patch -p1 -P 1009 -F2 popd %endif @@ -626,6 +706,9 @@ make install DESTDIR=%{buildroot} # google-cloud-sdk bundle %ifarch x86_64 pushd %{googlecloudsdk_dir} +# fix urllib3 CVEs +rm -rf lib/third_party/urllib3 +%{__python3} -m pip install --target lib/third_party --no-index --find-links %{_sourcedir} urllib3 mkdir -p %{buildroot}/usr/lib/%{name}/%{googlecloudsdk_dir} cp -a bin data lib %{buildroot}/usr/lib/%{name}/%{googlecloudsdk_dir} mkdir %{buildroot}/%{_bindir} @@ -654,6 +737,9 @@ popd # python-aliyun-sdk-core bundle pushd %{aliyunsdkcore_dir} %{__python3} setup.py install -O1 --skip-build --root %{buildroot} --install-lib /usr/lib/%{name}/%{bundled_lib_dir}/aliyun +# fix urllib3 CVEs +rm -rf %{buildroot}/usr/lib/%{name}/%{bundled_lib_dir}/aliyun/aliyunsdkcore/vendored/requests/packages/urllib3 +%{__python3} -m pip install --target %{buildroot}/usr/lib/%{name}/%{bundled_lib_dir}/aliyun/aliyunsdkcore/vendored/requests/packages --no-index --find-links %{_sourcedir} urllib3 popd # python-aliyun-sdk-ecs bundle @@ -674,6 +760,22 @@ mv %{buildroot}/%{_bindir}/aliyuncli %{buildroot}/%{_bindir}/aliyuncli-ra # aliyun_completer / aliyun_zsh_complete.sh rm %{buildroot}/%{_bindir}/aliyun_* popd + +# regular patch doesnt work in build-section +pushd %{buildroot}/usr/lib/%{name}/%{bundled_lib_dir} +/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=2 < %{PATCH1010} +/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=0 < %{PATCH1011} +popd +pushd %{buildroot}/usr/lib/%{name}/%{bundled_lib_dir}/gcp/google-cloud-sdk/lib/third_party +/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=0 < %{PATCH1012} +popd +pushd %{buildroot}/usr/lib/%{name}/%{bundled_lib_dir} +/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=0 < %{PATCH1013} +/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=0 < %{PATCH1014} +/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=0 < %{PATCH1015} +/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=0 < %{PATCH1016} +/usr/bin/patch --no-backup-if-mismatch -p1 --fuzz=2 < %{PATCH1017} +popd %endif ## tree fixup @@ -967,8 +1069,182 @@ ccs_update_schema > /dev/null 2>&1 ||: %{_usr}/lib/ocf/lib/heartbeat/OCF_*.pm %changelog -* Tue Nov 14 2023 Eduard Abdullin - 4.9.0-48.alma.1 -- findif.sh: dont use table parameter as it returns no netmask +* Tue May 26 2026 Andrew Lukoshko - 4.9.0-54.33.alma.1 +- Add AlmaLinux to RHEL-based distro detection in ocf-distro + +* Tue Apr 28 2026 Oyvind Albrigtsen - 4.9.0-54.33 +- bundled pyasn1: fix CVE-2026-30922 + Resolves: RHEL-157190 + +* Fri Apr 10 2026 Oyvind Albrigtsen - 4.9.0-54.32 +- db2: do not use db2stop to avoid divergence in the log + + Resolves: RHEL-166181 + +* Thu Mar 19 2026 Oyvind Albrigtsen - 4.9.0-54.31 +- db2: set reintegration when promotion is successful + + Resolves: RHEL-153157 + +* Fri Feb 27 2026 Oyvind Albrigtsen - 4.9.0-54.30 +- portblock: check inverse action state file for non-promotable + resources to avoid issues when doing e.g. block followed by unblock + + Resolves: RHEL-152316 + +* Thu Feb 5 2026 Oyvind Albrigtsen - 4.9.0-54.29 +- bundled urllib3: fix issue with CVE-2026-21441 patch + + Resolves: RHEL-146289 + +* Tue Jan 27 2026 Oyvind Albrigtsen - 4.9.0-54.28 +- bundled pyasn1: fix CVE-2026-23490 + + Resolves: RHEL-142448 + +* Tue Jan 20 2026 Oyvind Albrigtsen - 4.9.0-54.27 +- bundled urllib3: fix CVE-2025-66471 +- bundled urllib3: fix CVE-2026-21441 + + Resolves: RHEL-139760, RHEL-140787 + +* Tue Jan 6 2026 Oyvind Albrigtsen - 4.9.0-54.24 +- bundled urllib3: fix CVE-2025-66418 + + Resolves: RHEL-136031 + +* Fri Oct 31 2025 Oyvind Albrigtsen - 4.9.0-54.23 +- nfsserver: add ability to set e.g. "pipefs-directory=/run/nfs/rpc_pipefs" + in /etc/nfs.conf to avoid issues with non-clustered Kerberized mounts + + Resolves: RHEL-102979 + +* Thu Oct 30 2025 Oyvind Albrigtsen - 4.9.0-54.21 +- db2: fix monitor_retries_sleep variable name + + Resolves: RHEL-124815 + +* Tue Oct 21 2025 Oyvind Albrigtsen - 4.9.0-54.20 +- portblock: add promotable support, and method and status_check + parameters + + Resolves: RHEL-116150 + +* Mon Oct 20 2025 Oyvind Albrigtsen - 4.9.0-54.19 +- db2: use reintegration flag to avoid race condition on cluster + reintegration + + Resolves: RHEL-118625 + +* Thu Sep 18 2025 Oyvind Albrigtsen - 4.9.0-54.17 +- db2: add "skip_basic_sql_health_check" parameter to avoid failing on + systems with high load +- db2: add "monitor_retries", "monitor_sleep", and "monitor_retry_all_errors" + parameters to be able to avoid failing on first try + + Resolves: RHEL-115783, RHEL-115781 + +* Fri Aug 15 2025 Oyvind Albrigtsen - 4.9.0-54.16 +- bundled requests: fix CVE-2024-47081 + + Resolves: RHEL-104761 + +* Tue Jul 15 2025 Oyvind Albrigtsen - 4.9.0-54.15 +- ocf-shellfuncs/AWS agents: dont sleep after the final try in + curl_retry() + + Resolves: RHEL-102731 + +* Wed May 14 2025 Oyvind Albrigtsen - 4.9.0-54.13 +- Filesystem: add support for aznfs + + Resolves: RHEL-91257 + +* Fri Mar 28 2025 Oyvind Albrigtsen - 4.9.0-54.12 +- tomcat: fix CATALINA_PID not set, and catalina_base and catalina_out + parameter defaults + + Resolves: RHEL-85048 + +* Tue Mar 4 2025 Oyvind Albrigtsen - 4.9.0-54.11 +- AWS agents: reuse IMDS token until it expires + + Resolves: RHEL-81960 + +* Thu Feb 20 2025 Oyvind Albrigtsen - 4.9.0-54.10 +- portblock: fix iptables version detection + + Resolves: RHEL-79823 + +* Fri Jan 10 2025 Oyvind Albrigtsen - 4.9.0-54.8 +- openstack-cinder-volume: wait for volume to be available + + Resolves: RHEL-72956 + +* Wed Nov 27 2024 Oyvind Albrigtsen - 4.9.0-54.6 +- Filesystem: dont kill unrelated processes during stop-action + + Resolves: RHEL-69297 + +* Tue Oct 1 2024 Oyvind Albrigtsen - 4.9.0-54.5 +- nfsserver: also stop rpc-statd for nfsv4_only to avoid stop failing + in some cases + + Resolves: RHEL-61138 + +* Thu Jul 25 2024 Oyvind Albrigtsen - 4.9.0-54.4 +- bundled setuptools: fix CVE-2024-6345 + + Resolves: RHEL-50360 + +* Tue Jul 23 2024 Oyvind Albrigtsen - 4.9.0-54.3 +- gcp-pd-move: fix TLS_VERSION_1 issue + + Resolves: RHEL-50041 + +* Wed Jun 26 2024 Oyvind Albrigtsen - 4.9.0-54.2 +- bundled urllib3: fix CVE-2024-37891 + + Resolves: RHEL-44923 + +* Thu May 30 2024 Oyvind Albrigtsen - 4.9.0-54.1 +- AWS agents: retry failed metadata requests to avoid instantly + failing when there is a hiccup in the network or metadata service +- db2: fix OCF_SUCESS typo + + Resolves: RHEL-34137, RHEL-32828 + +* Thu Feb 8 2024 Oyvind Albrigtsen - 4.9.0-54 +- findif.sh: fix loopback IP handling + + Resolves: RHEL-15305 + +* Wed Jan 24 2024 Oyvind Albrigtsen - 4.9.0-53 +- bundled urllib3: fix CVE-2023-45803 +- bundled pycryptodome: fix CVE-2023-52323 + + Resolves: RHEL-22431, RHEL-20916 + +* Tue Nov 21 2023 Oyvind Albrigtsen - 4.9.0-52 +- findif: also check that netmaskbits != EOS + + Resolves: RHEL-17083 + +* Fri Nov 17 2023 Oyvind Albrigtsen - 4.9.0-51 +- aws-vpc-move-ip/aws-vpc-route53/awseip/awsvip: add auth_type parameter + and AWS Policy based authentication type + + Resolves: RHEL-16248 + +* Thu Nov 2 2023 Oyvind Albrigtsen - 4.9.0-49 +- exportfs: make "fsid" parameter optional + + Resolves: RHEL-15302 + +* Wed Sep 6 2023 Oyvind Albrigtsen - 4.9.0-48 +- mysql-common: improve error message + + Resolves: rhbz#1904465 * Thu Jul 20 2023 Oyvind Albrigtsen - 4.9.0-47 - Filesystem: improve stop-action and allow setting term/kill signals