1
0
mirror of https://github.com/OpenNebula/one.git synced 2025-02-04 17:47:00 +03:00

F #4985: Use qcow2 recover snaps instead blockcopy (#638)

This commit is contained in:
Jan Orel 2021-01-19 17:19:50 +01:00 committed by GitHub
parent 9b71bb9d66
commit fe6c2abf41
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 142 additions and 36 deletions

View File

@ -110,11 +110,13 @@ REPLICA_STORAGE_IP=$(awk 'gsub(/[\0]/, x)' \
# ------------------------------------------------------------------------------
# Synchronize Image Datastore in the Replica Host. Use a recovery snapshot
# if present in the RECOVERY_SNAPS_DIR
# (recovery snap existence means recreate is running, VMIDs is reused)
# ------------------------------------------------------------------------------
if recovery_snap_exists $REPLICA_HOST $VMID/$DST_FILE; then
# point to [disk].recovery_snaphost files
SRC_DIR=${REPLICA_RECOVERY_SNAPS_DIR}/$VMID
SRC_FILE="${DST_FILE}.recovery_snapshot"
SRC_FILE=$DST_FILE
SRC_PATH="$SRC_DIR/$SRC_FILE"
RECOVERY="YES"
else
@ -132,15 +134,24 @@ log "Cloning $SRC_PATH via replica $REPLICA_HOST in $DST"
# copy locally, we hit the replica
if [ "$REPLICA_HOST" = "$DST_HOST" ]; then
# if recovery snapshot is needed, prepare base <- base.1 qcow2 structure
CLONE_CMD=$(cat <<EOF
cd $SRC_DIR
cp $SRC_FILE $DST_PATH
# this only prints create_base function content
$(type create_base| grep -v 'is a function')
if [ -d $SRC_PATH.snap ]; then
cp -r $SRC_PATH.snap $DST_PATH.snap
if [ "$RECOVERY" != "YES" ] && [ -n "$RECOVERY_SNAPSHOT_FREQ" ]; then
create_base "$SRC_PATH" "$DST_PATH"
else
cd $SRC_DIR
cp $SRC_FILE $DST_PATH
if [ -d $SRC_PATH.snap ]; then
cp -r $SRC_PATH.snap $DST_PATH.snap
fi
fi
EOF
)
else
# copy to remote using faster tar|ssh
CLONE_CMD=$(cat <<EOF
@ -153,35 +164,45 @@ else
ssh $REPLICA_SSH_OPTS ${REPLICA_STORAGE_IP:-$DST_HOST} "$TAR xSf - -C $DST_DIR"
EOF
)
# if recovery snapshot is needed, prepare base <- base.1 qcow2 structure
if [ "$RECOVERY" != "YES" ] && [ -n "$RECOVERY_SNAPSHOT_FREQ" ]; then
MAKE_SNAP_CMD=$(cat <<EOF
# this only prints create_base function content
$(type create_base| grep -v 'is a function')
create_base "$DST_PATH" "$DST_PATH" "mv"
EOF
)
fi
fi
# Prepare uncopressed base image copy on REPLICA for recovery snapshots
# to speedup first rsync
# Prepare base image copy on REPLICA for recovery snapshots
if [ -n "$RECOVERY_SNAPSHOT_FREQ" ] && [ "$RECOVERY" != "YES" ]; then
SNAP_DIR="$REPLICA_RECOVERY_SNAPS_DIR/$VMID"
BASE_CMD=$(cat <<EOF
# TODO: Consider multiple subsequent recoveries
REPLICA_BASE_CMD=$(cat <<EOF
set -e -o pipefail
mkdir -p $SNAP_DIR
cd $SNAP_DIR
if file $SRC_PATH | grep -q QCOW; then
qemu-img convert -O qcow2 $SRC_PATH ${DST_FILE}.recovery_snapshot
else
cp $SRC_PATH ${DST_FILE}.recovery_snapshot
fi
mkdir -p $SNAP_DIR/$DST_FILE.snap
ln -f -s $DST_FILE.snap/base.1 $SNAP_DIR/$DST_FILE
cp $SRC_PATH $SNAP_DIR/$DST_FILE.snap/base
EOF
)
ssh_forward ssh_exec_and_log "$REPLICA_HOST" "$BASE_CMD" \
ssh_forward ssh_exec_and_log "$REPLICA_HOST" "$REPLICA_BASE_CMD" \
"Error uploading base image to replica"
fi
ssh_forward ssh_exec_and_log $REPLICA_HOST "$CLONE_CMD" \
"Error copying $SRC to $DST"
if [ -n "$MAKE_SNAP_CMD" ]; then
ssh_exec_and_log "$DST_HOST" "$MAKE_SNAP_CMD" \
"Error resizing image $DST"
fi
if [ -n "$RESIZE_CMD" ]; then
ssh_exec_and_log "$DST_HOST" "$RESIZE_CMD" \
"Error resizing image $DST"

View File

@ -70,7 +70,7 @@ for vm in $vms; do
if [ -n "$snap_ts" ] && [ "$rc" = "0" ]; then
vm_monitor="${vm_monitor}\nDISK_RECOVERY_SNAPSHOT = [ ID=${disk_id}, TIMESTAMP=${snap_ts}]"
else
vm_monitor="${vm_monitor}\nDISK_RECOVERY_SNAPSHOT = [ ID=${disk_id}, MSG=\"ERROR $rc\"]"
vm_monitor="${vm_monitor}\nDISK_RECOVERY_SNAPSHOT = [ ID=${disk_id}, MSG=\"ERROR $rc ${snap_ts}\"]"
fi
fi
fi

View File

@ -24,14 +24,13 @@ DISK_PATH=$2
FREQ=$3
REPLICA_HOST=$4
DRIVER_PATH=$(dirname $0)
source ${DRIVER_PATH}/../../etc/vmm/kvm/kvmrc
source ${DRIVER_PATH}/../../etc/tm/ssh/sshrc
source ${DRIVER_PATH}/../../scripts_common.sh
mkdir -p "${DISK_PATH}.snap"
SNAP_PATH="${DISK_PATH}.snap/recovery_snapshot"
SNAP_PATH="${DISK_PATH}.snap/rs_tmp"
DISK_NAME="$(basename $DISK_PATH)"
if [ -f $SNAP_PATH ]; then
@ -45,15 +44,45 @@ if [ -f $SNAP_PATH ]; then
fi
fi
if [ ! -L $DISK_PATH ]; then
echo "$DISK_PATH not a symlink"
exit 1
fi
# Enumerate disks for which we don't create snapshot (all except $DISK_PATH)
DISKS=$(virsh -c ${LIBVIRT_URI} domblklist one-${VMID} | grep disk | awk '{print $2}')
OTHER_DISK_STR=""
for DISK in $DISKS; do
[ "$DISK" = "$DISK_PATH" ] && continue
OTHER_DISK_STR+="--diskspec $DISK,snapshot=no "
done
# saves disk changes to base.1 moves active snap to rs_tmp
# paths needs to absolute, otherwise snapshot-create and blockcommit fails
touch $SNAP_PATH
SNAP_CMD=$(cat <<EOF
virsh -c ${LIBVIRT_URI} snapshot-create-as one-${VMID} recovery_snap \
--diskspec $DISK_PATH,file=$SNAP_PATH \
$OTHER_DISK_STR \
--disk-only --atomic --no-metadata
EOF
)
retry_if "active block job" 3 5\
virsh -q -c ${LIBVIRT_URI} blockcopy one-${VMID} \
--path ${DISK_PATH} --dest $SNAP_PATH --wait --finish
# try with quiesce first (needs guest agent)
$SNAP_CMD --quiesce || $SNAP_CMD
ssh $REPLICA_HOST "mkdir -p $REPLICA_RECOVERY_SNAPS_DIR/$VMID"
# copy base.1 to the replica
ssh $REPLICA_HOST "mkdir -p $REPLICA_RECOVERY_SNAPS_DIR/$VMID/$DISK_NAME.snap"
rsync -q $DISK_PATH.snap/base.1 \
$REPLICA_HOST:$REPLICA_RECOVERY_SNAPS_DIR/$VMID/$DISK_NAME.snap/ > /dev/null
rsync -q $SNAP_PATH \
$REPLICA_HOST:$REPLICA_RECOVERY_SNAPS_DIR/$VMID/${DISK_NAME}.recovery_snapshot > /dev/null
# reduce the backing-chain using blockcommit
# base <- base.1 <- rs_tmp is reduced to base <- base.1
# outdated rs_tmp is deleted next cycle
virsh -c ${LIBVIRT_URI} blockcommit one-${VMID} $SNAP_PATH \
--base $DISK_PATH.snap/base.1 \
--top $SNAP_PATH \
--active --pivot --wait
stat -c "%Y" $SNAP_PATH

View File

@ -25,15 +25,18 @@ DSID=$4
if [ -z "${ONE_LOCATION}" ]; then
TMCOMMON=/var/lib/one/remotes/tm/tm_common.sh
SSH_UTILS=/var/lib/one/remotes/tm/ssh/ssh_utils.sh
DATASTORES=/var/lib/one/datastores
else
TMCOMMON=$ONE_LOCATION/var/remotes/tm/tm_common.sh
SSH_UTILS=$ONE_LOCATION/var/remotes/tm/ssh/ssh_utils.sh
DATASTORES=$ONE_LOCATION/var/datastores
fi
DRIVER_PATH=$(dirname $0)
. $TMCOMMON
. $SSH_UTILS
SRC_PATH=$(arg_path $SRC)
SRC_HOST=$(arg_host $SRC)
@ -52,11 +55,12 @@ while IFS= read -r -d '' element; do
XPATH_ELEMENTS[i++]="$element"
done < <(onevm show -x $VMID| $XPATH \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/SOURCE \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CLONE)
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/CLONE \
/VM/TEMPLATE/DISK[DISK_ID=$DISK_ID]/RECOVERY_SNAPSHOT_FREQ)
DISK_SRC="${XPATH_ELEMENTS[j++]}"
CLONE="${XPATH_ELEMENTS[j++]}"
RECOVERY_SNAPSHOT_FREQ="${XPATH_ELEMENTS[j++]}"
SYSTEM_DS_PATH=$(dirname ${SRC_PATH})
IMAGE_DS_PATH=$(dirname ${DISK_SRC})
@ -68,12 +72,27 @@ SNAP_PATH="${SNAP_DIR}/${SNAP_ID}"
SNAP_PATH_RELATIVE=$(basename ${SNAP_PATH})
CURRENT_PATH=${DISK_PATH}
CMD=$(cat <<EOF
set -e -o pipefail
rm "${CURRENT_PATH}"
cp "${SNAP_PATH}" "${CURRENT_PATH}"
if [ -n "$RECOVERY_SNAPSHOT_FREQ" ]; then
CMD=$(cat <<EOF
# this only prints create_base function content
$(type create_base| grep -v 'is a function')
set -e -o pipefail
rm "${DISK_PATH}.snap/base"
rm "${DISK_PATH}.snap/base.1"
create_base "$SNAP_PATH" "$DISK_PATH"
EOF
)
else
CMD=$(cat <<EOF
set -e -o pipefail
rm "${CURRENT_PATH}"
cp "${SNAP_PATH}" "${CURRENT_PATH}"
EOF
)
fi
ssh_exec_and_log "${SRC_HOST}" "${CMD}" \
"Error reverting snapshot to ${SNAP_PATH}"

View File

@ -179,7 +179,33 @@ function recovery_snap_exists() {
local REPLICA_HOST=$1
local DISK=$2
SNAP_PATH="${REPLICA_RECOVERY_SNAPS_DIR}/$DISK.recovery_snapshot"
SNAP_PATH="${REPLICA_RECOVERY_SNAPS_DIR}/$DISK.snap"
ssh "$REPLICA_HOST" "test -f \"$SNAP_PATH\""
ssh "$REPLICA_HOST" "test -f \"$SNAP_PATH/base\" && test -f \"$SNAP_PATH/base.1\""
}
# ------------------------------------------------------------------------------
# Creates base + base.1 overlay qcow2 structure as following:
#
# $VM_DIR/disk.0 symlink -> disk.0.snap/base.1
# $VM_DIR/disk.0.snap dir
# $VM_DIR/disk.0.snap/disk.0.snap symlink -> . for relative referencing
# $VM_DIR/disk.0.snap/base base image (cp/mv from SRC_PATH)
# $VM_DIR/disk.0.snap/base.1 qcow2 overlay (backing file = base)
#
# ------------------------------------------------------------------------------
function create_base() {
local SRC_PATH=$1
local DST_PATH=$2
local COPY=${3:-cp}
DST_FILE=$(basename $DST_PATH)
mkdir -p $DST_PATH.snap
cd $DST_PATH.snap
ln -f -s . $DST_FILE.snap
$COPY $SRC_PATH base
qemu-img create -b $DST_FILE.snap/base -f qcow2 base.1
ln -f -s $DST_FILE.snap/base.1 $DST_PATH
cd -
}

View File

@ -42,6 +42,13 @@ get_size_and_format_of_disk_img() {
local PARAM="$2"
if [ -L "$QEMU_IMG_PATH" ]; then
TARGET=$(readlink "$QEMU_IMG_PATH")A
# symlink to disk.X.snap/base.1
if [[ "$TARGET" =~ disk.[0-9]*.snap/base.1 ]]; then
echo unknown qcow2-symlink
return
fi
# symlink, assume network disk
echo unknown network-disk
return
@ -143,6 +150,10 @@ else
create_target_disk_img "$DEST_HOST" "$DISK_PATH" "$SIZE"
MIGRATE_DISKS+="${MIGRATE_DISKS:+,}${DISK_DEV}"
elif [ "$FORMAT" = "qcow2-symlink" ]; then
# don't create disk, .snap dir will be copied anyway
MIGRATE_DISKS+="${MIGRATE_DISKS:+,}${DISK_DEV}"
elif [ "$FORMAT" = "network-disk" ]; then
true # skip
fi