mirror of
https://github.com/CiscoDevNet/cml-community.git
synced 2025-11-23 07:51:12 +00:00
1186 lines
36 KiB
Bash
1186 lines
36 KiB
Bash
#!/bin/bash
|
|
#
|
|
# This file is part of VIRL 2
|
|
# Copyright (c) 2019-2023, Cisco Systems, Inc.
|
|
# All rights reserved.
|
|
#
|
|
|
|
source /etc/default/virl2
|
|
|
|
# Version of this script in semver 2.0 format.
|
|
_VERSION="2.0.4"
|
|
|
|
# The branch from which to grab the canonical, stable latest version of the script.
|
|
GITHUB_BRANCH="master"
|
|
|
|
# This is the link to the raw GitHub source for the script itself.
|
|
GITHUB_URL="https://raw.githubusercontent.com/CiscoDevNet/cml-community/${GITHUB_BRANCH}/scripts/migration-tool/virl2-migrate-data.sh"
|
|
|
|
SRC_DIRS="${BASE_DIR}/images ${CFG_DIR}"
|
|
KEY_FILE="migration_key"
|
|
SSH_PORT="1122"
|
|
DOING_MIGRATION=0
|
|
DEFAULT_USER="sysadmin"
|
|
MIGRATION_MAP="/var/lib/libvirt/images:${LIBVIRT_IMAGES}"
|
|
HOSTNAME=$(hostname --short)
|
|
|
|
# Compute a timestamp, avoiding colons so that it's easier to use in filenames.
|
|
TIMESTAMP=$(printf '%(%Y-%m-%d_%H-%M-%S_%Z)T')
|
|
|
|
check_for_updates() {
|
|
gh_version=$(curl -s ${GITHUB_URL} | grep "^_VERSION")
|
|
if [ -z "${gh_version}" ]; then
|
|
echo "Unable to find version from GitHub source. Not updating."
|
|
return 1
|
|
fi
|
|
|
|
gh_version="_GH${gh_version}"
|
|
eval "${gh_version}"
|
|
|
|
if [ "${_GH_VERSION}" = "${_VERSION}" ]; then
|
|
echo "GitHub source version is the same as the current version. Not updating."
|
|
return 0
|
|
fi
|
|
|
|
curl -s --output ${LOCAL_ME} ${GITHUB_URL}
|
|
rc=$?
|
|
if [ ${rc} != 0 ]; then
|
|
echo "Failed to download GitHub source. Not updating."
|
|
return ${rc}
|
|
fi
|
|
|
|
chmod +x ${LOCAL_ME}
|
|
|
|
echo "Successfully updated to ${_GH_VERSION}. Please re-run ${LOCAL_ME}."
|
|
|
|
return 0
|
|
}
|
|
|
|
cleanup_backup() {
|
|
echo
|
|
echo "Cleaning up..."
|
|
echo
|
|
|
|
if [ -n "${tempd}" ]; then
|
|
rm -rf "${tempd}"
|
|
fi
|
|
if [ -n "${ddir}" ]; then
|
|
rm -rf "${ddir}"
|
|
fi
|
|
if [ -n "${ndir}" ]; then
|
|
rm -rf "${ndir}"
|
|
fi
|
|
if [ -n "${idir}" ]; then
|
|
rm -rf "${idir}"
|
|
fi
|
|
|
|
if [ ${DOING_MIGRATION} -eq 1 ]; then
|
|
umount_refplat_overlay 2>/dev/null
|
|
fi
|
|
|
|
restart_cml_services
|
|
|
|
if [ -z "${rc}" ]; then
|
|
rc=1
|
|
fi
|
|
|
|
if [ ${rc} != 0 ]; then
|
|
rm -f "${BACKUP_FILE}"
|
|
fi
|
|
|
|
exit ${rc}
|
|
}
|
|
|
|
cleanup_failed_restore() {
|
|
echo
|
|
echo "Cleaning up..."
|
|
echo
|
|
|
|
if [ -n "${ddir}" ]; then
|
|
rm -rf "${ddir}"
|
|
fi
|
|
if [ -n "${ndir}" ]; then
|
|
rm -rf "${ndir}"
|
|
fi
|
|
if [ -n "${idir}" ]; then
|
|
rm -rf "${idir}"
|
|
fi
|
|
|
|
restart_cml_services
|
|
|
|
if [ -z "${rc}" ]; then
|
|
rc=1
|
|
fi
|
|
|
|
exit ${rc}
|
|
}
|
|
|
|
cleanup_failed_from_host() {
|
|
echo
|
|
echo "Cleaning up..."
|
|
echo
|
|
|
|
if [ ${DOING_MIGRATION} -eq 1 ]; then
|
|
ssh -o "StrictHostKeyChecking=no" -i "${key_dir}"/${KEY_FILE} -p ${SSH_PORT} "${sysadmin_user}"@"${host}" "sudo /tmp/${ME} --umount-overlay"
|
|
fi
|
|
|
|
ssh -o "StrictHostKeyChecking=no" -i "${key_dir}"/${KEY_FILE} -p ${SSH_PORT} "${sysadmin_user}"@"${host}" "sudo /tmp/${ME} --start && sudo rm -rf ${libvirt_domains} && sudo rm -f /tmp/${ME} && sudo rm -f /etc/sudoers.d/cml-migrate && (cp -fa ~/.ssh/authorized_keys.migration ~/.ssh/authorized_keys >/dev/null 2>&1 || true)"
|
|
|
|
if [ -z "${rc}" ]; then
|
|
rc=1
|
|
fi
|
|
|
|
cleanup_from_host "${key_dir}"
|
|
|
|
exit ${rc}
|
|
}
|
|
|
|
set_virl_version() {
|
|
product_file=/PRODUCT
|
|
if [ $# = 1 ]; then
|
|
product_file=$1
|
|
fi
|
|
|
|
vers=$(jq -r ".PRODUCT_VERSION" <"${product_file}")
|
|
|
|
if [ $# = 1 ]; then
|
|
echo ${vers}
|
|
else
|
|
VIRL_VERSION=${vers}
|
|
fi
|
|
}
|
|
|
|
needs_overlay() {
|
|
major_ver=$(echo ${VIRL_VERSION} | cut -d'.' -f1)
|
|
minor_ver=$(echo ${VIRL_VERSION} | cut -d'.' -f2)
|
|
if [ "${major_ver}" -gt 2 ] || ([ "${major_ver}" -eq 2 ] && [ "${minor_ver}" -ge 3 ]); then
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
mount_refplat_overlay() {
|
|
if ! needs_overlay; then
|
|
return 0
|
|
fi
|
|
|
|
# create required directories, if needed
|
|
[ -d $REF_PLAT/cdrom ] || mkdir -p $REF_PLAT/cdrom
|
|
[ -d $REF_PLAT/diff ] || mkdir -p $REF_PLAT/diff
|
|
[ -d $REF_PLAT/work ] || mkdir -p $REF_PLAT/work
|
|
|
|
if [ $REF_PLAT != $LIBVIRT_IMAGES ]; then
|
|
MOUNT_POINT=$REF_PLAT/cdrom
|
|
else
|
|
MOUNT_POINT=$LIBVIRT_IMAGES
|
|
fi
|
|
|
|
# if overlayfs is mounted, do nothing
|
|
mount | grep -q "^overlay on $LIBVIRT_IMAGES"
|
|
if [ $? -eq 0 ]; then
|
|
return 0
|
|
fi
|
|
|
|
# try to mount the CDROM. If none is present it will continue
|
|
# it will just give an error for the mount like
|
|
# "mount: /var/local/virl2/refplat/cdrom: no medium found on /dev/sr0."
|
|
if [ -f "$REF_PLAT_ISO_IMAGE" ]; then
|
|
! test -d $MOUNT_POINT && mkdir $MOUNT_POINT
|
|
if ! mount -t iso9660 -oloop,fscontext=$CONTEXT $REF_PLAT_ISO_IMAGE $MOUNT_POINT; then
|
|
echo "no refplat ISO image present / mounted!"
|
|
return 1
|
|
fi
|
|
elif [ -d "$REF_PLAT_DIR" ]; then
|
|
if test -d "$REF_PLAT_DIR"; then
|
|
test -d $MOUNT_POINT && rmdir $MOUNT_POINT
|
|
ln -s $REF_PLAT_DIR $MOUNT_POINT
|
|
else
|
|
echo "no refplat ISO image present / mounted!"
|
|
return 1
|
|
fi
|
|
else
|
|
! test -d $MOUNT_POINT && mkdir $MOUNT_POINT
|
|
if ! mount $CDROM_DEVICE; then
|
|
echo "no refplat CD-ROM present / mounted!"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
# mount the libvirt image directory in an OverlayFS
|
|
if [ $REF_PLAT != $LIBVIRT_IMAGES ]; then
|
|
mount -t overlay overlay \
|
|
-ofscontext=$CONTEXT,lowerdir=$REF_PLAT/cdrom,upperdir=$REF_PLAT/diff,workdir=$REF_PLAT/work \
|
|
$LIBVIRT_IMAGES
|
|
if [ $? != 0 ]; then
|
|
echo "error mounting overlay filesystem"
|
|
return 1
|
|
fi
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
umount_refplat_overlay() {
|
|
if ! needs_overlay; then
|
|
return 0
|
|
fi
|
|
|
|
umount ${LIBVIRT_IMAGES}
|
|
return $?
|
|
}
|
|
|
|
build_local_src_dirs() {
|
|
if [ ${DOING_MIGRATION} -eq 1 ]; then
|
|
return
|
|
fi
|
|
|
|
# In CML 2.3+ we no longer have the overlay.
|
|
if ! needs_overlay; then
|
|
SRC_DIRS="${SRC_DIRS} ${LIBVIRT_IMAGES}"
|
|
return
|
|
fi
|
|
|
|
if [ "${REF_PLAT}" != "${LIBVIRT_IMAGES}" ]; then
|
|
MOUNT_POINT=${REF_PLAT}/cdrom
|
|
else
|
|
MOUNT_POINT=${LIBVIRT_IMAGES}
|
|
fi
|
|
|
|
if [ -d "${REF_PLAT_DIR}" ]; then
|
|
MOUNT_POINT="${REF_PLAT_DIR}"
|
|
fi
|
|
|
|
WRKDIR="${REF_PLAT}"/diff
|
|
|
|
# Find all custom node defs
|
|
new_node_defs=$(find "${WRKDIR}"/node-definitions/ -maxdepth 1 -type f -name "*.yaml")
|
|
old_IFS=${IFS}
|
|
IFS='
|
|
'
|
|
for nd in ${new_node_defs}; do
|
|
fname=$(basename "${nd}")
|
|
if [ ! -f "${MOUNT_POINT}"/node-definitions/"${fname}" ]; then
|
|
SRC_DIRS="${SRC_DIRS} ${nd}"
|
|
else
|
|
if ! diff -q "${nd}" "${MOUNT_POINT}"/node-definitions/"${fname}" >/dev/null 2>&1; then
|
|
SRC_DIRS="${SRC_DIRS} ${nd}"
|
|
fi
|
|
fi
|
|
done
|
|
|
|
# Find all custom image defs
|
|
new_image_defs=$(find "${WRKDIR}"/virl-base-images/ -maxdepth 1 -type d)
|
|
|
|
for id in ${new_image_defs}; do
|
|
if [ "${id}" = "${WRKDIR}"/virl-base-images/ ]; then
|
|
continue
|
|
fi
|
|
dname=$(basename "${id}")
|
|
if [ ! -d "${MOUNT_POINT}"/virl-base-images/"${dname}" ]; then
|
|
SRC_DIRS="${SRC_DIRS} ${id}"
|
|
fi
|
|
done
|
|
|
|
IFS=${old_IFS}
|
|
}
|
|
|
|
export_network_configuration() {
|
|
outfile=${CFG_DIR}/migration_info.txt
|
|
printf "# CML2 migration on $(date).\n" >> ${outfile}
|
|
printf "\n## nmcli con show \n" >> ${outfile}
|
|
nmcli con show >> ${outfile}
|
|
printf "\n## ip link show \n" >> ${outfile}
|
|
ip link show >> ${outfile}
|
|
printf "\n## nmcli con show bridge0 \n" >> ${outfile}
|
|
nmcli con show bridge0 >> ${outfile}
|
|
printf "\n## nmcli \n" >> ${outfile}
|
|
nmcli >> ${outfile}
|
|
printf "\n## hostname \n" >> ${outfile}
|
|
hostname >> ${outfile}
|
|
}
|
|
|
|
export_libvirt_domains() {
|
|
ddir=$(mktemp -d /tmp/libvirt_domains.XXXXX)
|
|
domains=$(virsh list --all --name)
|
|
if [ $? != 0 ]; then
|
|
echo "${ddir}"
|
|
return $?
|
|
fi
|
|
|
|
old_IFS=${IFS}
|
|
IFS='
|
|
'
|
|
|
|
for domain in ${domains}; do
|
|
virsh dumpxml "${domain}" >"${ddir}"/"${domain}".xml
|
|
done
|
|
|
|
IFS=${old_IFS}
|
|
|
|
echo "${ddir}"
|
|
}
|
|
|
|
export_libvirt_networks() {
|
|
ndir=$(mktemp -d /tmp/libvirt_networks.XXXXX)
|
|
networks=$(virsh net-list --all --name | grep -v "^default")
|
|
if [ $? != 0 ]; then
|
|
echo "${ndir}"
|
|
return $?
|
|
fi
|
|
|
|
old_IFS=${IFS}
|
|
IFS='
|
|
'
|
|
|
|
for network in ${networks}; do
|
|
virsh net-dumpxml "${network}" >"${ndir}"/"${network}".xml
|
|
done
|
|
|
|
IFS=${old_IFS}
|
|
|
|
echo "${ndir}"
|
|
}
|
|
|
|
export_libvirt_ifaces() {
|
|
idir=$(mktemp -d /tmp/libvirt_ifaces.XXXXX)
|
|
ifaces=$(virsh net-list --all | grep "^[[:space:]]*bridge" | awk '{print $1}' | grep -v "^bridge0")
|
|
if [ $? != 0 ]; then
|
|
echo "${idir}"
|
|
return $?
|
|
fi
|
|
|
|
old_IFS=${IFS}
|
|
IFS='
|
|
'
|
|
|
|
for iface in ${ifaces}; do
|
|
virsh iface-dumpxml "${iface}" --inactive >"${idir}"/"${iface}".xml
|
|
done
|
|
|
|
IFS=${old_IFS}
|
|
|
|
echo "${idir}"
|
|
}
|
|
|
|
define_domains() {
|
|
ddir=$1
|
|
|
|
if [ ! -d "${ddir}" ]; then
|
|
echo "${ddir}: No such directory"
|
|
return 1
|
|
fi
|
|
|
|
ls -1 "${ddir}"/*.xml >/dev/null 2>&1
|
|
if [ $? != 0 ]; then
|
|
return 0
|
|
fi
|
|
|
|
old_IFS=${IFS}
|
|
IFS='
|
|
'
|
|
|
|
for domain in "${ddir}"/*.xml; do
|
|
virsh define "${domain}"
|
|
if [ $? != 0 ]; then
|
|
rc=$?
|
|
IFS=${old_IFS}
|
|
return ${rc}
|
|
fi
|
|
done
|
|
|
|
IFS=${old_IFS}
|
|
}
|
|
|
|
define_networks() {
|
|
ndir=$1
|
|
|
|
if [ ! -d "${ndir}" ]; then
|
|
echo "${ndir}: No such directory"
|
|
return 1
|
|
fi
|
|
|
|
ls -1 "${ndir}"/*.xml >/dev/null 2>&1
|
|
if [ $? != 0 ]; then
|
|
return 0
|
|
fi
|
|
|
|
old_IFS=${IFS}
|
|
IFS='
|
|
'
|
|
|
|
for network in "${ndir}"/*.xml; do
|
|
virsh net-define "${network}"
|
|
if [ $? != 0 ]; then
|
|
rc=$?
|
|
IFS=${old_IFS}
|
|
return ${rc}
|
|
fi
|
|
done
|
|
|
|
IFS=${old_IFS}
|
|
}
|
|
|
|
define_ifaces() {
|
|
idir=$1
|
|
|
|
if [ ! -d "${idir}" ]; then
|
|
echo "${idir}: No such directory"
|
|
return 1
|
|
fi
|
|
|
|
ls -1 "${idir}"/*.xml >/dev/null 2>&1
|
|
if [ $? != 0 ]; then
|
|
return 0
|
|
fi
|
|
|
|
old_IFS=${IFS}
|
|
IFS='
|
|
'
|
|
|
|
for iface in "${idir}"/*.xml; do
|
|
virsh iface-define "${iface}"
|
|
if [ $? != 0 ]; then
|
|
rc=$?
|
|
IFS=${old_IFS}
|
|
return ${rc}
|
|
fi
|
|
done
|
|
|
|
IFS=${old_IFS}
|
|
}
|
|
|
|
delete_libvirt_domains() {
|
|
for domain in $(virsh list --all --name); do
|
|
virsh undefine "${domain}" >/dev/null
|
|
done
|
|
}
|
|
|
|
delete_libvirt_networks() {
|
|
for network in $(virsh net-list --all --name | grep -v "^default"); do
|
|
virsh net-undefine "${network}" >/dev/null
|
|
done
|
|
}
|
|
|
|
delete_libvirt_ifaces() {
|
|
for iface in $(virsh iface-list --all | grep "^[[:space:]]*bridge" | awk '{print $1}' | grep -v "^bridge0"); do
|
|
virsh iface-undefine "${iface}" >/dev/null
|
|
done
|
|
}
|
|
|
|
check_disk_space() {
|
|
source=$1
|
|
target=$2
|
|
|
|
if [ -z "${source}" ] && [ $# = 3 ]; then
|
|
total_needed=$3
|
|
else
|
|
total_needed=$(du -B1 -sc ${source} | grep total | sed -E -s 's|\s+total||')
|
|
fi
|
|
|
|
total_available=$(df -B1 --output=avail "${target}" | grep -E '[0-9]')
|
|
|
|
if [ "${total_needed}" -gt "${total_available}" ]; then
|
|
echo "Insufficient disk space required in ${target}; ${total_needed} bytes required but only ${total_available} bytes available."
|
|
return 1
|
|
fi
|
|
|
|
return 0
|
|
}
|
|
|
|
wait_for_vms_to_stop() {
|
|
# this is only needed if VMs are running on the
|
|
# controller where the ISO is mounted.
|
|
loops=5 # max 5x5 = 25s
|
|
done=0
|
|
while ((loops > 0 && !done)); do
|
|
done=1
|
|
for vm in $(virsh -c qemu:///system list --all --name); do
|
|
if [[ "$vm" =~ ^[0-9a-f]{8}-([0-9a-f]{4}-){3}[0-9a-f]{12} ]]; then
|
|
vm_state=$(virsh dominfo "$vm")
|
|
if [[ "$vm_state" =~ State:\ +running ]]; then
|
|
echo "still running: $vm"
|
|
done=0
|
|
fi
|
|
fi
|
|
done
|
|
((loops -= 1))
|
|
((!done)) && sleep 5
|
|
done
|
|
if ((!done)); then
|
|
echo "Some labs are still running; please stop all labs before continuing"
|
|
return 1
|
|
fi
|
|
}
|
|
|
|
stop_cml_services() {
|
|
#wait_for_vms_to_stop
|
|
rc=$?
|
|
if [ ${rc} != 0 ]; then
|
|
return ${rc}
|
|
fi
|
|
systemctl stop virl2.target
|
|
rc=$?
|
|
if [ ${rc} != 0 ]; then
|
|
return ${rc}
|
|
fi
|
|
|
|
echo "Waiting for controller to become inactive..."
|
|
while [ "$(systemctl is-active virl2-controller)" = "active" ]; do
|
|
echo " Still active..."
|
|
sleep 5
|
|
done
|
|
return ${rc}
|
|
}
|
|
|
|
restart_cml_services() {
|
|
echo "Restarting CML services..."
|
|
systemctl start virl2.target
|
|
}
|
|
|
|
delete_local_dirs() {
|
|
dirs=$1
|
|
|
|
from=""
|
|
if [ $# -ge 2 ]; then
|
|
from=$2
|
|
fi
|
|
|
|
for dir in ${dirs}; do
|
|
echo "Deleting local directory ${from}${dir}"
|
|
rm -rf "${from}""${dir}"
|
|
if [ $# -lt 3 ]; then
|
|
echo "Creating directory ${from}${dir}"
|
|
mkdir -p "${from}""${dir}"
|
|
fi
|
|
done
|
|
}
|
|
|
|
generate_ssh_key() {
|
|
# Generate an SSH key we can use to avoid re-prompting for a password.
|
|
tempd=$(mktemp -d /tmp/migration.XXXXX)
|
|
ssh-keygen -b 4096 -q -N "" -f "${tempd}"/${KEY_FILE}
|
|
echo "${tempd}"
|
|
}
|
|
|
|
cleanup_from_host() {
|
|
key_dir=$1
|
|
|
|
rm -rf "${key_dir}"
|
|
restart_cml_services
|
|
}
|
|
|
|
check_cml_versions() {
|
|
curr_ver=$1
|
|
src_ver=$2
|
|
|
|
if [ "${curr_ver}" = "${src_ver}" ]; then
|
|
return 0
|
|
fi
|
|
|
|
# Allow one to migrate from 2.2.x to 2.3+.
|
|
if echo "${curr_ver}" | grep -qE '^2\.[3-9]\.[0-9]' && echo "${src_ver}" | grep -qE '^2\.2\.'; then
|
|
DOING_MIGRATION=1
|
|
return 0
|
|
fi
|
|
|
|
return 1
|
|
}
|
|
|
|
sync_from_host() {
|
|
host=$1
|
|
host_ip="${host}"
|
|
# used in scp/rsync commands to support ipv6
|
|
scp_rsync_host="${host}"
|
|
if echo "${host_ip}" | grep -qE '[a-zA-Z]'; then
|
|
host_ip=$(host -t A "${host_ip}" | grep -oE '[0-9][0-9.]+')
|
|
if [ $? != 0 ]; then
|
|
echo "Failed to lookup host ${host}. Please specify a valid IP or hostname."
|
|
return 1
|
|
fi
|
|
elif echo "${host_ip}" | grep -qE '([0-9a-fA-F:]{1,5}){3,8}'; then
|
|
scp_rsync_host=\["${host}"\]
|
|
fi
|
|
if ip addr show | grep -q "inet6* ${host_ip}/"; then
|
|
echo "You are trying to migrate from the local host. Please specify another host from which to migrate."
|
|
return 1
|
|
fi
|
|
|
|
if ! nc -z "${host}" ${SSH_PORT}; then
|
|
echo "Remote host does not have OpenSSH enabled; start the OpenSSH service from Cockpit on the source host."
|
|
return 1
|
|
fi
|
|
|
|
if [ ${NO_CONFIRM} -eq 0 ]; then
|
|
read -r -p "Do you wish to import data from ${host}? [y/N] " confirm
|
|
echo
|
|
if echo "${confirm}" | grep -viq '^y'; then
|
|
echo "Terminating import."
|
|
return 0
|
|
fi
|
|
fi
|
|
|
|
stop_cml_services || (
|
|
echo "Failed to stop CML services."
|
|
exit $?
|
|
)
|
|
delete_libvirt_domains
|
|
delete_libvirt_networks
|
|
delete_libvirt_ifaces
|
|
|
|
key_dir=$(generate_ssh_key)
|
|
key=$(cat "${key_dir}"/${KEY_FILE}.pub)
|
|
|
|
printf "\nThe next prompt will be for %s's password on %s.\n" "${sysadmin_user}" "${host}"
|
|
printf "The prompt following that will be for %s's password on %s to enter sudo mode.\n\n" "${sysadmin_user}" "${host}"
|
|
# Stop the service on the remote host and make sure we don't need
|
|
# a password for sudo. We also install the SSH pubkey for subsequent logins.
|
|
if ! ssh -o "StrictHostKeyChecking=no" -t -p ${SSH_PORT} "${sysadmin_user}"@"${host}" "echo '%${sysadmin_user} ALL=(ALL) NOPASSWD: ALL' | sudo tee /etc/sudoers.d/cml-migrate >/dev/null 2>&1 && mkdir -p ~/.ssh && \
|
|
chmod 0700 ~/.ssh && (cp -fa ~/.ssh/authorized_keys ~/.ssh/authorized_keys.migration >/dev/null 2>&1 || true) && echo ${key} | tee -a ~/.ssh/authorized_keys >/dev/null 2>&1 && chmod 0600 ~/.ssh/authorized_keys"; then
|
|
rc=$?
|
|
cleanup_from_host "${key_dir}"
|
|
echo "Error preparing ${host} for migration."
|
|
return ${rc}
|
|
fi
|
|
|
|
# Install this script on the remote host.
|
|
if ! scp -o "StrictHostKeyChecking=no" -i "${key_dir}"/${KEY_FILE} -P ${SSH_PORT} "${LOCAL_ME}" "${sysadmin_user}"@"${scp_rsync_host}":"/tmp/${ME}" >/dev/null; then
|
|
rc=$?
|
|
cleanup_from_host "${key_dir}"
|
|
echo "Error copying /usr/local/bin/${ME} to source host."
|
|
return ${rc}
|
|
fi
|
|
|
|
# Stop CML services on remote host.
|
|
if ! ssh -o "StrictHostKeyChecking=no" -i "${key_dir}"/${KEY_FILE} -p ${SSH_PORT} "${sysadmin_user}"@"${host}" "sudo chmod +x /tmp/${ME} && sudo /tmp/${ME} --stop" 2>/dev/null; then
|
|
rc=$?
|
|
cleanup_from_host "${key_dir}"
|
|
echo "Failed to stop source CML services."
|
|
return ${rc}
|
|
fi
|
|
|
|
trap cleanup_failed_from_host SIGINT
|
|
|
|
# Check CML versions on both hosts.
|
|
output=$( (ssh -o "StrictHostKeyChecking=no" -i "${key_dir}"/${KEY_FILE} -p ${SSH_PORT} "${sysadmin_user}"@"${host}" "sudo /tmp/${ME} --cml-version") 2>/dev/null)
|
|
if [ $? != 0 ]; then
|
|
rc=$?
|
|
cleanup_from_host "${key_dir}"
|
|
echo "Failed to determine remote CML version."
|
|
return ${rc}
|
|
fi
|
|
|
|
if ! check_cml_versions ${VIRL_VERSION} ${output}; then
|
|
cleanup_from_host "${key_dir}"
|
|
echo "Migration between versions is not supported. Source server version: ${output}, Dest server version: ${VIRL_VERSION}."
|
|
return 1
|
|
fi
|
|
|
|
if [ ${DOING_MIGRATION} -eq 1 ]; then
|
|
(ssh -o "StrictHostKeyChecking=no" -i "${key_dir}"/${KEY_FILE} -p ${SSH_PORT} "${sysadmin_user}"@"${host}" "sudo /tmp/${ME} --mount-overlay") 2>/dev/null
|
|
if [ $? != 0 ]; then
|
|
rc=$?
|
|
cleanup_from_host "${key_dir}"
|
|
return ${rc}
|
|
fi
|
|
fi
|
|
|
|
migr_arg=""
|
|
if [ ${DOING_MIGRATION} -eq 1 ]; then
|
|
migr_arg="--migration"
|
|
fi
|
|
# Build the list of remote src dirs.
|
|
output=$( (ssh -o "StrictHostKeyChecking=no" -i "${key_dir}"/${KEY_FILE} -p ${SSH_PORT} "${sysadmin_user}"@"${host}" "sudo /tmp/${ME} ${migr_arg} --src-dirs") 2>/dev/null)
|
|
if [ $? != 0 ]; then
|
|
rc=$?
|
|
cleanup_from_host "${key_dir}"
|
|
echo "Failed to obtain remote src dirs."
|
|
return ${rc}
|
|
fi
|
|
|
|
SRC_DIRS=${output}
|
|
delete_local_dirs "${SRC_DIRS}"
|
|
|
|
# Get the list of domains from virsh.
|
|
libvirt_domains=$( (ssh -o "StrictHostKeyChecking=no" -i "${key_dir}"/${KEY_FILE} -p ${SSH_PORT} "${sysadmin_user}"@"${host}" "sudo /tmp/${ME} --get-domains") 2>/dev/null)
|
|
if [ $? != 0 ]; then
|
|
rc=$?
|
|
cleanup_from_host "${key_dir}"
|
|
echo "Failed to get libvirt domains from ${host}: ${libvirt_domains}"
|
|
return ${rc}
|
|
fi
|
|
|
|
# Get the list of networks from virsh
|
|
libvirt_networks=$( (ssh -o "StrictHostKeyChecking=no" -i "${key_dir}"/${KEY_FILE} -p ${SSH_PORT} "${sysadmin_user}"@"${host}" "sudo /tmp/${ME} --get-networks") 2>/dev/null)
|
|
if [ $? != 0 ]; then
|
|
rc=$?
|
|
cleanup_from_host "${key_dir}"
|
|
echo "Failed to get libvirt networks from ${host}: ${libvirt_networks}"
|
|
return ${rc}
|
|
fi
|
|
|
|
# Get the list of ifaces from virsh
|
|
libvirt_ifaces=$( (ssh -o "StrictHostKeyChecking=no" -i "${key_dir}"/${KEY_FILE} -p ${SSH_PORT} "${sysadmin_user}"@"${host}" "sudo /tmp/${ME} --get-ifaces") 2>/dev/null)
|
|
if [ $? != 0 ]; then
|
|
rc=$?
|
|
cleanup_from_host "${key_dir}"
|
|
echo "Failed to get libvirt ifaces from ${host}: ${libvirt_ifaces}"
|
|
return ${rc}
|
|
fi
|
|
|
|
SRC_DIRS="${SRC_DIRS} ${libvirt_domains} ${libvirt_networks} ${libvirt_ifaces}"
|
|
|
|
echo "Migrating ${SRC_DIRS} to this CML server..."
|
|
space_dirs=""
|
|
if [ ${DOING_MIGRATION} -eq 1 ]; then
|
|
for map_dir in ${MIGRATION_MAP}; do
|
|
space_dirs="${space_dirs} $(echo "${map_dir}" | cut -d':' -f1)"
|
|
done
|
|
fi
|
|
|
|
# Get required disk space from remote host
|
|
output=$( (ssh -o "StrictHostKeyChecking=no" -i "${key_dir}"/${KEY_FILE} -p ${SSH_PORT} "${sysadmin_user}"@"${host}" "sudo du -B1 -sc ${SRC_DIRS} ${space_dirs} | grep total | sed -E -s 's|\s+total||'") 2>/dev/null)
|
|
if check_disk_space "" ${BASE_DIR} "${output}"; then
|
|
printf "Starting migration. Please be patient, migration may take a while....\n\n\n"
|
|
sdirs=""
|
|
for src_dir in ${SRC_DIRS}; do
|
|
sdirs="${sdirs} ${sysadmin_user}"@"${scp_rsync_host}":"${src_dir}"
|
|
done
|
|
rsync -aAvzXR --progress --checksum --rsync-path="sudo rsync" --exclude="*.rej" --exclude="*.orig" -e "ssh -o StrictHostKeyChecking=no -i ${key_dir}/${KEY_FILE} -p ${SSH_PORT}" ${sdirs} /
|
|
# output=$( (ssh -o "StrictHostKeyChecking=no" -i "${key_dir}"/${KEY_FILE} -p ${SSH_PORT} sysadmin@"${host}" "sudo tar --acls --selinux -cpf - ${SRC_DIRS}" | tar -C / --acls --selinux -xpf -) 2>&1 )
|
|
rc=$?
|
|
if [ ${rc} != 0 ]; then
|
|
echo "Migration completed with errors. See the output above for details."
|
|
else
|
|
# Migrate each mapped src dir to its target dir.
|
|
success=1
|
|
if [ ${DOING_MIGRATION} -eq 1 ]; then
|
|
for map_dir in ${MIGRATION_MAP}; do
|
|
src_dir=${sysadmin_user}@${scp_rsync_host}:$(echo "${map_dir}" | cut -d':' -f1)
|
|
dest_dir=$(dirname $(echo "${map_dir}" | cut -d':' -f2))
|
|
delete_local_dirs "$(echo "${map_dir}" | cut -d':' -f2)"
|
|
rsync -aAvzX --progress --checksum --rsync-path="sudo rsync" --exclude="*.rej" --exclude="*.orig" -e "ssh -o StrictHostKeyChecking=no -i ${key_dir}/${KEY_FILE} -p ${SSH_PORT}" "${src_dir}" "${dest_dir}"
|
|
rc=$?
|
|
if [ ${rc} != 0 ]; then
|
|
echo "Migration completed with errors. See the output above for details."
|
|
success=0
|
|
break
|
|
fi
|
|
done
|
|
fi
|
|
if [ ${success} = 1 ]; then
|
|
if [ ${DOING_MIGRATION} -eq 0 ]; then
|
|
# For each of the libvirt domains, migrate the XML.
|
|
echo "Migrating libvirt domains..."
|
|
output=$(define_domains "${libvirt_domains}" 2>&1)
|
|
rc=$?
|
|
echo "Libvirt domain output is '${output}'"
|
|
if [ ${rc} != 0 ]; then
|
|
echo "Libvirt domain import completed with errors:"
|
|
printf '%s\n\n' "${output}"
|
|
else
|
|
# For each of the libvirt networks, migrate the XML.
|
|
echo "Migrating libvirt networks..."
|
|
output=$(define_networks "${libvirt_networks}" 2>&1)
|
|
rc=$?
|
|
echo "Libvirt network output is '${output}'"
|
|
if [ ${rc} != 0 ]; then
|
|
echo "Libvirt network import completed with errors:"
|
|
printf '%s\n\n' "${output}"
|
|
else
|
|
# For each of the libvirt ifaces, migrate the XML.
|
|
echo "Migrating libvirt ifaces..."
|
|
output=$(define_ifaces "${libvirt_ifaces}" 2>&1)
|
|
rc=$?
|
|
echo "Libvirt iface output is '${output}'"
|
|
if [ ${rc} != 0 ]; then
|
|
echo "Libvirt network import completed with errors:"
|
|
printf '%s\n\n' "${output}"
|
|
else
|
|
echo "Migration completed SUCCESSFULLY."
|
|
echo "Please make sure you have either mounted the same refplat ISO on or copied its contents to this CML server."
|
|
fi
|
|
fi
|
|
fi
|
|
else
|
|
printf "\nData transfer completed SUCCESSFULLY.\n"
|
|
echo "Performing configuration migration..."
|
|
output=$( (cd "${BASE_DIR}"/db_migrations && env CFG_DIR="${CFG_DIR}" BASE_DIR="${BASE_DIR}" VIRL2_DIR="${BASE_DIR}" HOME="${BASE_DIR}" MIGRATION_LIBVIRT_DOM_XML_DIR="${libvirt_domains}" MIGRATION_LIBVIRT_NET_XML_DIR="${libvirt_networks}" MIGRATION_LIBVIRT_IF_XML_DIR="${libvirt_ifaces}" COMPUTE_ID="${COMPUTE_ID}" MIGRATION=1 HOSTNAME="${HOSTNAME}" "${BASE_DIR}"/.local/bin/alembic upgrade head) 2>&1)
|
|
rc=$?
|
|
# This feels hacky, but we need to do it.
|
|
chown -R www-data:www-data "${CFG_DIR}"
|
|
find "${BASE_DIR}"/images -type f \( -name "*.img" -or -name "nodedisk*" \) -print0 | xargs -0 chown libvirt-qemu:kvm 2>/dev/null
|
|
if [ ${rc} != 0 ]; then
|
|
echo "Failed to execute data upgrade script:"
|
|
printf '%s\n\n' "${output}"
|
|
else
|
|
echo "Migration completed SUCCESSFULLY."
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
else
|
|
rc=$?
|
|
fi
|
|
|
|
printf "\nFinishing up with the remote host..."
|
|
if [ ${DOING_MIGRATION} -eq 1 ]; then
|
|
ssh -o "StrictHostKeyChecking=no" -i "${key_dir}"/${KEY_FILE} -p ${SSH_PORT} "${sysadmin_user}"@"${host}" "sudo /tmp/${ME} --umount-overlay"
|
|
fi
|
|
|
|
if ! ssh -o "StrictHostKeyChecking=no" -i "${key_dir}"/${KEY_FILE} -p ${SSH_PORT} "${sysadmin_user}"@"${host}" "sudo /tmp/${ME} --start && sudo rm -rf ${libvirt_domains} && sudo rm -rf ${libvirt_networks} && sudo rm -rf ${libvirt_ifaces} && sudo rm -f /tmp/${ME} && sudo rm -f /etc/sudoers.d/cml-migrate && (cp -fa ~/.ssh/authorized_keys.migration ~/.ssh/authorized_keys >/dev/null 2>&1 || true)"; then
|
|
printf "FAILED.\n"
|
|
echo "Error finishing up on remote host. Check to make sure the CML services are running on ${host}."
|
|
rc=$?
|
|
else
|
|
printf "DONE.\n"
|
|
fi
|
|
|
|
rm -rf "${key_dir}"
|
|
rm -rf "${libvirt_domains}"
|
|
rm -rf "${libvirt_networks}"
|
|
rm -rf "${libvirt_ifaces}"
|
|
|
|
restart_cml_services
|
|
|
|
return ${rc}
|
|
}
|
|
|
|
ME=$(basename "$0")
|
|
LOCAL_ME=$0
|
|
set_virl_version
|
|
|
|
if [ "$EUID" != 0 ]; then
|
|
echo "This script must be run as root. Use 'sudo' to run it."
|
|
exit 1
|
|
fi
|
|
|
|
opts=$(getopt -o brf:h:vdu: --long host:,file:,backup,restore,cml-version,src-dirs,stop,start,get-domains,get-networks,get-ifaces,mount-overlay,umount-overlay,migration,no-confirm,user,version,update -- "$@")
|
|
if [ $? != 0 ]; then
|
|
echo "usage: $0 -h|--host HOST_TO_MIGRATE_FROM"
|
|
echo " OR"
|
|
echo " $0 -b|--backup|-r|--restore -f|--file PATH_TO_BACKUP_FILE"
|
|
exit 1
|
|
fi
|
|
|
|
REMOTE_HOST=
|
|
BACKUP_FILE=
|
|
BACKUP=0
|
|
RESTORE=0
|
|
GET_SRC_DIRS=0
|
|
NO_CONFIRM=0
|
|
|
|
sysadmin_user=${DEFAULT_USER}
|
|
|
|
eval set -- "$opts"
|
|
while true; do
|
|
case "$1" in
|
|
-h | --host)
|
|
shift
|
|
REMOTE_HOST=$1
|
|
;;
|
|
-f | --file)
|
|
shift
|
|
BACKUP_FILE=$1
|
|
;;
|
|
-b | --backup)
|
|
BACKUP=1
|
|
;;
|
|
-m | --migration)
|
|
DOING_MIGRATION=1
|
|
;;
|
|
-r | --restore)
|
|
RESTORE=1
|
|
;;
|
|
--cml-version)
|
|
echo ${VIRL_VERSION}
|
|
exit 0
|
|
;;
|
|
-u | --user)
|
|
shift
|
|
sysadmin_user=$1
|
|
;;
|
|
-d | --src-dirs)
|
|
GET_SRC_DIRS=1
|
|
;;
|
|
--stop)
|
|
stop_cml_services
|
|
exit $?
|
|
;;
|
|
--start)
|
|
restart_cml_services
|
|
exit $?
|
|
;;
|
|
--get-domains)
|
|
export_libvirt_domains
|
|
exit $?
|
|
;;
|
|
--get-networks)
|
|
export_libvirt_networks
|
|
exit $?
|
|
;;
|
|
--get-ifaces)
|
|
export_libvirt_ifaces
|
|
exit $?
|
|
;;
|
|
--mount-overlay)
|
|
mount_refplat_overlay
|
|
exit $?
|
|
;;
|
|
--umount-overlay)
|
|
umount_refplat_overlay
|
|
exit $?
|
|
;;
|
|
--no-confirm)
|
|
NO_CONFIRM=1
|
|
;;
|
|
-v | --version)
|
|
echo "${_VERSION}"
|
|
exit 0
|
|
;;
|
|
--update)
|
|
check_for_updates
|
|
exit $?
|
|
;;
|
|
--)
|
|
shift
|
|
break
|
|
;;
|
|
esac
|
|
shift
|
|
done
|
|
|
|
if [ ${GET_SRC_DIRS} -eq 1 ]; then
|
|
build_local_src_dirs
|
|
echo ${SRC_DIRS}
|
|
exit 0
|
|
fi
|
|
|
|
if [ -n "${REMOTE_HOST}" ] && [ -n "${BACKUP_FILE}" ]; then
|
|
echo "Only one of --host or --file may be specified."
|
|
exit 1
|
|
fi
|
|
|
|
if [ -z "${REMOTE_HOST}" ] && [ -z "${BACKUP_FILE}" ]; then
|
|
echo "One of --host or --file must be specified."
|
|
exit 1
|
|
fi
|
|
|
|
if [ -n "${REMOTE_HOST}" ]; then
|
|
sync_from_host "${REMOTE_HOST}"
|
|
exit $?
|
|
fi
|
|
|
|
if [ ${BACKUP} = 1 ] && [ ${RESTORE} = 1 ]; then
|
|
echo "Only one of --backup or --restore can be specified."
|
|
exit 1
|
|
fi
|
|
|
|
if [ ${BACKUP} = 0 ] && [ ${RESTORE} = 0 ]; then
|
|
echo "One of --backup or --restore must be specified."
|
|
exit 1
|
|
fi
|
|
|
|
if [ ${RESTORE} = 1 ]; then
|
|
if [ ! -f "${BACKUP_FILE}" ]; then
|
|
echo "Backup file ${BACKUP_FILE} does not exist or is not a file."
|
|
exit 1
|
|
fi
|
|
|
|
DOING_MIGRATION=0
|
|
|
|
# While not all data may go to the product root, the way CML's file system
|
|
# is laid out means it's almost certainly going to be on the same FS.
|
|
if ! check_disk_space "${BACKUP_FILE}" ${BASE_DIR}; then
|
|
exit $?
|
|
fi
|
|
|
|
if [ ${NO_CONFIRM} -eq 0 ]; then
|
|
read -r -p "Do you wish to restore from ${BACKUP_FILE}? This will overwrite current local data. [y/N] " confirm
|
|
echo
|
|
if echo "${confirm}" | grep -qiv '^y'; then
|
|
echo "Terminating restore."
|
|
exit 0
|
|
fi
|
|
fi
|
|
|
|
# First, extract /PRODUCT from the backup and check that the version matches the current version.
|
|
tempd=$(mktemp -d /tmp/migration.XXXXX)
|
|
output=$(tar -C "${tempd}" --acls --selinux -xpf "${BACKUP_FILE}" PRODUCT libvirt_domains.dat libvirt_networks.dat libvirt_ifaces.dat 2>&1)
|
|
rc=$?
|
|
if [ ${rc} != 0 ]; then
|
|
echo "Failed to extract /PRODUCT and libvirt data from backup:"
|
|
printf '%s\n\n' "${output}"
|
|
exit ${rc}
|
|
fi
|
|
|
|
virl_version=$(set_virl_version "${tempd}"/PRODUCT)
|
|
# This will set DOING_MIGRATION if needed.
|
|
if ! check_cml_versions ${VIRL_VERSION} "${virl_version}"; then
|
|
rm -rf "${tempd}"
|
|
echo "Versions do not match or migration path not supported. Source server version: ${virl_version}, Dest server version: ${VIRL_VERSION}."
|
|
exit 1
|
|
fi
|
|
|
|
ddir=$(cat "${tempd}"/libvirt_domains.dat)
|
|
ndir=$(cat "${tempd}"/libvirt_networks.dat)
|
|
idir=$(cat "${tempd}"/libvirt_ifaces.dat)
|
|
|
|
rm -rf "${tempd}"
|
|
|
|
stop_cml_services || (
|
|
echo "Failed to stop CML services."
|
|
exit $?
|
|
)
|
|
delete_libvirt_domains
|
|
delete_libvirt_networks
|
|
delete_libvirt_ifaces
|
|
|
|
trap cleanup_failed_restore SIGINT
|
|
|
|
echo "Restoring ${BACKUP_FILE} to local CML. Please be patient, this may take a while..."
|
|
sdirs=""
|
|
if [ ${DOING_MIGRATION} -eq 1 ]; then
|
|
for sdir in ${SRC_DIRS}; do
|
|
# Remove the leading '/' to match what's in the tar file.
|
|
sdirs="${sdirs} $(echo "${sdir}" | cut -d'/' -f2-)"
|
|
done
|
|
# Add the directory that contains the libvirt domains.
|
|
sdirs="${sdirs} $(echo "${ddir}" | cut -d'/' -f2-)"
|
|
# Add the directory that contains the libvirt networks.
|
|
sdirs="${sdirs} $(echo "${ndir}" | cut -d'/' -f2-)"
|
|
# Add the directory that contains the libvirt ifaces.
|
|
sdirs="${sdirs} $(echo "${idir}" | cut -d'/' -f2-)"
|
|
echo "Extracting ${sdirs} from the backup..."
|
|
fi
|
|
|
|
delete_local_dirs "$(tar -tf "${BACKUP_FILE}" | grep '/$')" "/" 0
|
|
export total=$(du -shc ${BACKUP_FILE} -B10k --apparent-size | tail -1 | cut -f1)
|
|
tar -C / --acls --selinux --checkpoint=2000 --checkpoint-action=exec=' printf "\e[1;31m%s of %s extracted %d/100%% complete \e[0m\r" $(numfmt --to=iec-i $((10000*${TAR_CHECKPOINT})) ) $(numfmt --to=iec-i $((10000*${total})) )\t$((100*${TAR_CHECKPOINT}/${total})) ' --exclude=PRODUCT --exclude="libvirt*.dat" -xvpf "${BACKUP_FILE}"
|
|
rc=$?
|
|
if [ ${rc} != 0 ]; then
|
|
echo "Restore failed with error. See output above for the error details."
|
|
else
|
|
if [ ${DOING_MIGRATION} -eq 1 ]; then
|
|
printf "\nRestore completed SUCCESSFULLY.\n"
|
|
echo "Performing configuration migration..."
|
|
output=$( (cd "${BASE_DIR}"/db_migrations && env CFG_DIR="${CFG_DIR}" BASE_DIR="${BASE_DIR}" VIRL2_DIR="${BASE_DIR}" HOME="${BASE_DIR}" MIGRATION_LIBVIRT_DOM_XML_DIR="${ddir}" MIGRATION_LIBVIRT_NET_XML_DIR="${ndir}" MIGRATION_LIBVIRT_IF_XML_DIR="${idir}" COMPUTE_ID="${COMPUTE_ID}" MIGRATION=1 HOSTNAME="${HOSTNAME}" "${BASE_DIR}"/.local/bin/alembic upgrade head) 2>&1)
|
|
rc=$?
|
|
# This feels hacky, but we need to do it.
|
|
chown -R www-data:www-data "${CFG_DIR}"
|
|
find "${BASE_DIR}"/images -type f \( -name "*.img" -or -name "nodedisk*" \) -print0 | xargs -0 chown libvirt-qemu:kvm 2>/dev/null
|
|
if [ ${rc} != 0 ]; then
|
|
echo "Failed to execute data upgrade script:"
|
|
printf '%s\n\n' "${output}"
|
|
else
|
|
echo "Migration completed SUCCESSFULLY."
|
|
fi
|
|
else
|
|
output=$(define_domains "${ddir}" 2>&1)
|
|
rc=$?
|
|
if [ ${rc} != 0 ]; then
|
|
echo "Libvirt domain import completed with errors:"
|
|
printf '%s\n\n' "${output}"
|
|
else
|
|
output=$(define_networks "${ndir}" 2>&1)
|
|
rc=$?
|
|
if [ ${rc} != 0 ]; then
|
|
echo "Libvirt network import completed with errors:"
|
|
printf '%s\n\n' "${output}"
|
|
else
|
|
output=$(define_ifaces "${idir}" 2>&1)
|
|
rc=$?
|
|
if [ ${rc} != 0 ]; then
|
|
echo "Libvirt iface import completed with errors:"
|
|
printf '%s\n\n' "${output}"
|
|
else
|
|
echo "Restore completed SUCCESSFULLY."
|
|
echo "Please make sure you have either mounted the same refplat ISO on or copied its contents to this CML server."
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
fi
|
|
|
|
rm -rf "${ddir}"
|
|
rm -rf "${ndir}"
|
|
rm -rf "${idir}"
|
|
|
|
restart_cml_services
|
|
|
|
exit ${rc}
|
|
fi
|
|
|
|
if [ ${DOING_MIGRATION} -eq 0 ]; then
|
|
build_local_src_dirs
|
|
else
|
|
for mig_dir in ${MIGRATION_MAP}; do
|
|
SRC_DIRS="${SRC_DIRS} $(echo "${mig_dir}" | cut -d':' -f1)"
|
|
done
|
|
fi
|
|
|
|
BACKUP_FILE=$(realpath "${BACKUP_FILE}")
|
|
|
|
# We are doing a dump to a single tar file.
|
|
if ! check_disk_space "${SRC_DIRS}" "$(dirname "${BACKUP_FILE}")"; then
|
|
exit $?
|
|
fi
|
|
|
|
if [ ${NO_CONFIRM} -eq 0 ]; then
|
|
read -r -p "Are you sure you want to backup? Doing so will restart the CML services. [y/N] " confirm
|
|
echo
|
|
if echo "${confirm}" | grep -qiv '^y'; then
|
|
echo "Terminating backup."
|
|
exit 0
|
|
fi
|
|
fi
|
|
|
|
# Before stopping the services, fetch the diagnostics and put it in a folder to include in the backup.
|
|
/usr/bin/curl -sk ip6-localhost:8001/api/internal/diagnostics > $CFG_DIR/diagnostics-$TIMESTAMP.log
|
|
|
|
stop_cml_services || (
|
|
echo "Failed to stop CML services."
|
|
exit $?
|
|
)
|
|
|
|
trap cleanup_backup SIGINT
|
|
|
|
if [ ${DOING_MIGRATION} -eq 1 ]; then
|
|
mount_refplat_overlay
|
|
if [ $? != 0 ]; then
|
|
exit $?
|
|
fi
|
|
fi
|
|
|
|
ddir=$(export_libvirt_domains)
|
|
ndir=$(export_libvirt_networks)
|
|
idir=$(export_libvirt_ifaces)
|
|
tempd=$(mktemp -d /tmp/migration.XXXXX)
|
|
cd "${tempd}" || (
|
|
echo "Failed to cd to ${tempd}"
|
|
exit $?
|
|
)
|
|
echo "${ddir}" >libvirt_domains.dat
|
|
echo "${ndir}" >libvirt_networks.dat
|
|
echo "${idir}" >libvirt_ifaces.dat
|
|
|
|
# Try to preserve some info about the server's network configuration.
|
|
export_network_configuration
|
|
|
|
SRC_DIRS="${SRC_DIRS} ${ddir} ${ndir} ${idir}"
|
|
|
|
echo "Backing up ${SRC_DIRS}..."
|
|
|
|
echo "Backing up CML data to ${BACKUP_FILE}. Please be patient, this may take a while..."
|
|
export total=$(du -shc /PRODUCT ${SRC_DIRS} libvirt_domains.dat libvirt_networks.dat libvirt_ifaces.dat -B10k --apparent-size | tail -1 | cut -f1)
|
|
tar -C "${tempd}" --acls --selinux --checkpoint=2000 --exclude="*.rej" --exclude="*.orig" --checkpoint-action=exec=' printf "\e[1;31m%s of %s copied %d/100%% complete \e[0m\r" $(numfmt --to=iec-i $((10000*${TAR_CHECKPOINT})) ) $(numfmt --to=iec-i $((10000*${total})) )\t$((100*${TAR_CHECKPOINT}/${total})) ' -cvpf "${BACKUP_FILE}" /PRODUCT libvirt_domains.dat libvirt_networks.dat libvirt_ifaces.dat ${SRC_DIRS}
|
|
rc=$?
|
|
echo
|
|
if [ ${rc} != 0 ]; then
|
|
echo "Backup completed with errors. See the output above for the error details."
|
|
else
|
|
echo "Backup completed SUCCESSFULLY. Backup file is ${BACKUP_FILE}."
|
|
fi
|
|
|
|
cleanup_backup
|