blob: b102a1a866bbd868c91db17ad6286c395b19b351 [file]
#!/bin/bash
# Licensed to the Apache Software Foundation (ASF) under one
# or more contributor license agreements. See the NOTICE file
# distributed with this work for additional information
# regarding copyright ownership. The ASF licenses this file
# to you under the Apache License, Version 2.0 (the
# "License"); you may not use this file except in compliance
# with the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
# KIND, either express or implied. See the License for the
# specific language governing permissions and limitations
# under the License.
help() {
printf "Usage: $0
-i identifier (required for CLI compatibility; value ignored by local-only heartbeat)
-p path (required for CLI compatibility; value ignored by local-only heartbeat)
-m mount point (local path where heartbeat will be written)
-h host (host IP/name to include in heartbeat filename)
-r write/read hb log (read-check mode)
-c cleanup (trigger emergency reboot)
-t interval between read hb log\n"
exit 1
}
#set -x
NfsSvrIP=
NfsSvrPath=
MountPoint=
HostIP=
interval=
rflag=0
cflag=0
while getopts 'i:p:m:h:t:rc' OPTION
do
case $OPTION in
i)
NfsSvrIP="$OPTARG"
;; # retained for CLI compatibility but unused for this script
p)
NfsSvrPath="$OPTARG"
;; # retained for CLI compatibility but unused for this script
m)
MountPoint="$OPTARG"
;;
h)
HostIP="$OPTARG"
;;
r)
rflag=1
;;
t)
interval="$OPTARG"
;;
c)
cflag=1
;;
*)
help
;;
esac
done
# For heartbeat we require a mountpoint
if [ -z "$MountPoint" ]
then
echo "Mount point (-m) is required"
help
fi
# Validate mount point exists, is (if possible) a mounted filesystem, and is writable
if [ ! -d "$MountPoint" ]; then
echo "Mount point directory does not exist: $MountPoint" >&2
exit 1
fi
# If the 'mountpoint' utility is available, ensure this is an actual mount
if command -v mountpoint >/dev/null 2>&1; then
if ! mountpoint -q "$MountPoint"; then
echo "Mount point is not a mounted filesystem: $MountPoint" >&2
exit 1
fi
fi
# Ensure the mount point is writable
if [ ! -w "$MountPoint" ]; then
echo "Mount point is not writable: $MountPoint" >&2
exit 1
fi
#delete VMs on this mountpoint (best-effort)
deleteVMs() {
local mountPoint=$1
# ensure it ends with a single trailing slash
mountPoint="${mountPoint%/}/"
vmPids=$(ps aux | grep qemu | grep "$mountPoint" | awk '{print $2}' 2> /dev/null)
if [ -z "$vmPids" ]
then
return
fi
for pid in $vmPids
do
kill -9 $pid &> /dev/null
done
}
#checking is there the mount point present under $MountPoint?
if grep -q "^[^ ]\+ $MountPoint " /proc/mounts
then
# mount exists; nothing to do here; keep for compatibility with original flow
:
else
# mount point not present
# if not in read-check mode, consider deleting VMs similar to original behavior
if [ "$rflag" == "0" ]
then
deleteVMs $MountPoint
fi
fi
hbFolder="$MountPoint/KVMHA"
hbFile="$hbFolder/hb-$HostIP"
write_hbLog() {
#write the heart beat log
stat "$hbFile" &> /dev/null
if [ $? -gt 0 ]
then
# create a new one
mkdir -p "$hbFolder" &> /dev/null
# touch will be done by atomic write below; ensure folder is writable
if [ ! -w "$hbFolder" ]; then
printf "Folder not writable: $hbFolder" >&2
return 2
fi
fi
timestamp=$(date +%s)
# Write atomically to avoid partial writes (write to tmp then mv)
tmpfile="${hbFile}.$$"
printf "%s\n" "$timestamp" > "$tmpfile" 2>/dev/null
if [ $? -ne 0 ]; then
printf "Failed to write heartbeat to $tmpfile" >&2
return 2
fi
mv -f "$tmpfile" "$hbFile" 2>/dev/null
return $?
}
check_hbLog() {
hb_diff=0
if [ ! -f "$hbFile" ]; then
# signal large difference if file missing
hb_diff=999999
return 1
fi
now=$(date +%s)
hb=$(cat "$hbFile" 2>/dev/null)
if [ -z "$hb" ]; then
hb_diff=999998
return 1
fi
diff=`expr $now - $hb 2>/dev/null`
if [ $? -ne 0 ]
then
hb_diff=999997
return 1
fi
if [ -z "$interval" ]; then
# if no interval provided, consider 0 as success
if [ $diff -gt 0 ]; then
hb_diff=$diff
return 1
else
hb_diff=0
return 0
fi
fi
if [ $diff -gt $interval ]
then
hb_diff=$diff
return 1
fi
hb_diff=0
return 0
}
if [ "$rflag" == "1" ]
then
check_hbLog
status=$?
diff="${hb_diff:-0}"
if [ $status -eq 0 ]
then
echo "=====> ALIVE <====="
else
echo "=====> Considering host as DEAD because last write on [$hbFile] was [$diff] seconds ago, but the max interval is [$interval] <======"
fi
exit 0
elif [ "$cflag" == "1" ]
then
/usr/bin/logger -t heartbeat "kvmsmpheartbeat.sh will reboot system because it was unable to write the heartbeat to the storage."
sync &
sleep 5
echo b > /proc/sysrq-trigger
exit $?
else
write_hbLog
exit $?
fi