mirror of https://github.com/apache/cloudstack.git
219 lines
5.1 KiB
Bash
Executable File
219 lines
5.1 KiB
Bash
Executable 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
|