Skip to content

Commit 5add651

Browse files
wip
1 parent c477494 commit 5add651

File tree

1 file changed

+41
-29
lines changed

1 file changed

+41
-29
lines changed

backup/kvm_vm_backup/kmv_backup_refactored.sh

Lines changed: 41 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -57,63 +57,79 @@ EOF
5757
exit 1
5858
}
5959

60-
# start new log.
61-
starting_log() {
62-
mkdir -p "$BACKUP_DIR/$ACTIVEVM"
60+
init_log() {
61+
(( LOG_INITIALIZED )) && return
62+
mkdir -p "$(dirname "$LOGFILE")"
6363
exec >> >(tee -a "$LOGFILE") 2>&1
64-
echo "$(date +'%Y-%m-%d %H:%M:%S') Starting backup of $ACTIVEVM"
64+
LOG_INITIALIZED=1
6565
}
6666

67+
start_log() {
68+
mkdir -p "$BACKUP_DIR/$ACTIVEVM"
69+
echo "$(date +'%Y-%m-%d %H:%M:%S') Starting backup of $ACTIVEVM"
70+
}
6771
# backup config of VM.
6872
backup_vm_config() {
6973
virsh dumpxml "$ACTIVEVM" >"$BACKUP_DIR/$ACTIVEVM/$ACTIVEVM".xml
7074
echo "$(date '+%Y-%m-%d %H:%M:%S') Saved $ACTIVEVM domain XML"
7175
}
7276

77+
# double‑checks the path we are about to delete.
78+
safe_rm() {
79+
local target="$1"
80+
[[ -z "$target" || "$target" == "/" ]] && fatal "Refusing to remove empty or root path"
81+
[[ ! -e "$target" ]] && fatal "safe_rm: '$target' does not exist"
82+
rm -rf --one-file-system -- "$target"
83+
}
84+
7385
# Getting a list and a path of disk images.
7486
vm_disks_get() {
7587
# robust domblklist parsing using separator
76-
mapfile -t DISK_INFO < <(virsh domblklist --details --type disk --noheadings --separator '|' "$ACTIVEVM")
88+
mapfile -t DISK_INFO < <(virsh domblklist --details --type disk --noheadings --separator '|' "$ACTIVEVM" 2>/dev/null)
7789
DISK_LIST=()
7890
DISK_PATH=()
7991
for line in "${DISK_INFO[@]}"; do
80-
IFS='|' read -r _dev _type target source <<<"$line"
92+
IFS='|' read -r target source _type _dev <<<"$line"
8193
DISK_LIST+=("$target")
8294
DISK_PATH+=("$source")
8395
done
84-
echo "$(date '+%Y-%m-%d %H:%M:%S') Disk targets: ${DISK_LIST[*]}"
85-
echo "$(date '+%Y-%m-%d %H:%M:%S') Disk paths : ${DISK_PATH[*]}"
96+
echo "$(date '+%Y-%m-%d %H:%M:%S') Disk targets: ${DISK_LIST[*]}";
97+
echo "$(date '+%Y-%m-%d %H:%M:%S') Disk paths : ${DISK_PATH[*]}";
8698
}
8799

88100
# Getting a block device which is a snapshot.
89-
get_vm_shapshots() {
101+
get_snapshots() {
90102
virsh snapshot-list --domain "$ACTIVEVM" --no-metadata --name 2>/dev/null || true
91103
}
92104

105+
93106
# Entry point.
94107
set -euo pipefail
95108
IFS=$'\n\t'
109+
shopt -s nocasematch
96110

97111
[[ $# -lt 2 ]] && usage
98-
COMMAND_USE="$1"
99-
shift
112+
COMMAND_USE="$1"; shift
100113

101114
[[ $EUID -ne 0 ]] && fatal "Please run as root (e.g. sudo $0 ...)"
102115

103116
case "$COMMAND_USE" in
104-
--active | --stopped | --clean) ;;
105-
*) usage ;;
117+
--active|--stopped|--clean) ;;
118+
*) usage ;;
106119
esac
107120

121+
LOG_INITIALIZED=0
122+
init_log
123+
108124
for ACTIVEVM in "$@"; do
109-
SNAPSHOT_NAME="snapshot-$(date +%s)"
125+
SNAPSHOT_NAME="snapshot-${ACTIVEVM}-$(date +%s%N)"
110126
start_log
111127
backup_vm_config
112128
vm_disks_get
113129

114130
if [[ $COMMAND_USE == "--active" ]]; then
115131
echo "Creating live snapshot $SNAPSHOT_NAME for $ACTIVEVM"
116-
if ! get_snapshots | grep -q "$SNAPSHOT_NAME"; then
132+
if ! get_snapshots | grep -Fxq "$SNAPSHOT_NAME"; then
117133
virsh snapshot-create-as --domain "$ACTIVEVM" "$SNAPSHOT_NAME" --disk-only \
118134
--atomic --quiesce --no-metadata
119135
else
@@ -125,43 +141,39 @@ for ACTIVEVM in "$@"; do
125141

126142
for SRC in "${DISK_PATH[@]}"; do
127143
FILENAME=$(basename "$SRC")
128-
[[ "$SRC" == "-" || "$SRC" =~ \\.iso$ || "$SRC" =~ \\.ISO$ ]] && {
129-
echo "Skip removable/media: $SRC"
130-
continue
131-
}
132-
echo "Copying $SRC -> $BACKUP_DIR/$ACTIVEVM/$FILENAME"
144+
[[ "$SRC" == "-" || "$SRC" == *.iso ]] && { echo "Skip removable/media: $SRC" && continue; }
145+
echo "Copying $SRC -> $BACKUP_DIR/$ACTIVEVM/$FILENAME";
133146
cp --reflink=auto --sparse=always "$SRC" "$BACKUP_DIR/$ACTIVEVM/$FILENAME"
134147
done
135148

136149
# commit + remove snapshot layer
137150
for disk in "${DISK_LIST[@]}"; do
138151
virsh blockcommit "$ACTIVEVM" "$disk" --active --verbose --pivot || echo "Nothing to commit for $disk"
139152
done
153+
vm_disks_get
140154
# remove snapshot file(s)
141-
for snap in $(get_snapshots); do
142-
echo "Removing snapshot file $snap"
143-
safe_rm "$snap" || true
155+
for p in "${DISK_PATH[@]}"; do
156+
[[ $p == *.snapshot ]] || continue
157+
echo "Removing leftover snapshot layer $p"
158+
rm -f -- "$p"
144159
done
145160
echo "Backup of $ACTIVEVM finished"
146161

147162
elif [[ $COMMAND_USE == "--stopped" ]]; then
148163
echo "Shutting down $ACTIVEVM"
149164
virsh shutdown "$ACTIVEVM" || true
150165
COUNTER=40 # 40*3=120s
151-
while virsh list | grep -q " $ACTIVEVM " && ((COUNTER-- > 0)); do
166+
while virsh list --name | grep -Fxq "$ACTIVEVM" && (( COUNTER-- > 0 )); do
152167
sleep 3
153168
done
154-
if virsh list | grep -q " $ACTIVEVM "; then
169+
if virsh list --name | grep -Fxq "$ACTIVEVM"; then
155170
echo "Force‑off $ACTIVEVM"
156171
virsh destroy "$ACTIVEVM"
157172
fi
158173

159174
for SRC in "${DISK_PATH[@]}"; do
160175
FILENAME=$(basename "$SRC")
161-
[[ "$SRC" == "-" || "$SRC" =~ \\.iso$ || "$SRC" =~ \\.ISO$ ]] && {
162-
echo "Skip removable/media: $SRC"
163-
continue
164-
}
176+
[[ "$SRC" == "-" || "$SRC" == *.iso ]] && { echo "Skip removable/media: $SRC" && continue; }
165177
cp --reflink=auto --sparse=always "$SRC" "$BACKUP_DIR/$ACTIVEVM/$FILENAME"
166178
done
167179

0 commit comments

Comments
 (0)