mirror of
https://github.com/lephisto/crossover.git
synced 2025-12-06 04:09:20 +01:00
Compare commits
4 Commits
284cfb6e76
...
v0.8
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ce325beec | ||
|
|
b8d2386e69 | ||
|
|
a5ea397d11 | ||
|
|
36dabe9d79 |
100
crossover
100
crossover
@@ -16,8 +16,9 @@ declare opt_influx_summary_metrics='crossover_jobs'
|
||||
# Cross Pool Migration and incremental replication Tool for Proxmox VMs using Ceph.
|
||||
# Author: Bastian Mäuser <bma@netz.org>
|
||||
|
||||
declare -r VERSION=0.7
|
||||
declare -r NAME=$(basename "$0")
|
||||
name=$(basename "$0")
|
||||
declare -r NAME=$name
|
||||
declare -r VERSION=0.8
|
||||
declare -r PROGNAME=${NAME%.*}
|
||||
|
||||
declare -r PVE_DIR="/etc/pve"
|
||||
@@ -28,7 +29,8 @@ declare -r EXT_CONF='.conf'
|
||||
declare -r PVFORMAT_FULL='e:%t r:%e c:%r a:%a %b %p'
|
||||
declare -r PVFORMAT_SNAP='e:%t c:%r a:%a %b'
|
||||
|
||||
declare -r LOG_FILE=$(mktemp)
|
||||
logfile=$(mktemp)
|
||||
declare -r LOG_FILE=$logfile
|
||||
|
||||
declare -A -g pvnode
|
||||
declare -A -g dstpvnode
|
||||
@@ -51,6 +53,8 @@ declare -g -i perf_bytes_total=0
|
||||
declare -g -i perf_vm_running=0
|
||||
declare -g -i perf_vm_stopped=0
|
||||
declare -g -i perf_snaps_removed=0
|
||||
declare -g -i perf_vm_total=0
|
||||
declare -g -i perf_vm_ok=0
|
||||
|
||||
declare opt_destination
|
||||
declare opt_vm_ids=''
|
||||
@@ -75,6 +79,7 @@ declare -r redstconf='^\/etc\/pve\/nodes\/(.*)\/qemu-server\/([0-9]+).conf$'
|
||||
declare -r recephimg='([a-zA-Z0-9]+)\:(.*)'
|
||||
declare -r restripsnapshots='/^$/,$d'
|
||||
declare -r redateex='^([0-9]{4})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})([0-9]{2})$'
|
||||
declare -r restripansicolor='s/\x1b\[[0-9;]*m//g'
|
||||
|
||||
function usage(){
|
||||
shift
|
||||
@@ -117,9 +122,10 @@ Options:
|
||||
--influxtoken Influx API token with write permission
|
||||
--influxbucket Influx Bucket to write to (e.g. --influxbucket=telegraf/autogen)
|
||||
--jobname Descriptive name for the job, used in Statistics
|
||||
--mail Mail address to send report to, comma-seperated (e.g. --mail=admin@test.com,admin2@test.com)
|
||||
Switches:
|
||||
--online Allow online Copy
|
||||
--migrate Stop VM on Source Cluster before final Transfer and restart on destination Cluster
|
||||
--migrate Stop VM on Source Cluster before final Transfer and start on destination Cluster
|
||||
--nolock Don't lock source VM on Transfer (mainly for test purposes)
|
||||
--keep-slock Keep source VM locked on Transfer
|
||||
--keep-dlock Keep VM locked after transfer on Destination
|
||||
@@ -129,7 +135,6 @@ Switches:
|
||||
Report bugs to <mephisto@mephis.to>
|
||||
|
||||
EOF
|
||||
exit 1
|
||||
}
|
||||
|
||||
function parse_opts(){
|
||||
@@ -139,7 +144,7 @@ function parse_opts(){
|
||||
local args
|
||||
args=$(getopt \
|
||||
--options '' \
|
||||
--longoptions=vmid:,prefixid:,excludevmids:,destination:,pool:,keeplocal:,keepremote:,rewrite:,influxurl:,influxorg:,influxtoken:,influxbucket:,jobname:,online,migrate,nolock,keep-slock,keep-dlock,overwrite,dry-run,debug \
|
||||
--longoptions=vmid:,prefixid:,excludevmids:,destination:,pool:,keeplocal:,keepremote:,rewrite:,influxurl:,influxorg:,influxtoken:,influxbucket:,jobname:,mail:,online,migrate,nolock,keep-slock,keep-dlock,overwrite,dry-run,debug,syslog \
|
||||
--name "$PROGNAME" \
|
||||
-- "$@") \
|
||||
|| end_process 128
|
||||
@@ -161,6 +166,7 @@ function parse_opts(){
|
||||
--influxtoken) opt_influx_token=$2; shift 2;;
|
||||
--influxbucket) opt_influx_bucket=$2; shift 2;;
|
||||
--jobname) opt_influx_jobname=$2; shift 2;;
|
||||
--mail) opt_addr_mail="$2"; shift 2;;
|
||||
--online) opt_online=1; shift ;;
|
||||
--migrate) opt_migrate=1; shift ;;
|
||||
--dry-run) opt_dry_run=1; shift;;
|
||||
@@ -169,6 +175,7 @@ function parse_opts(){
|
||||
--keep-slock) opt_keepslock=1; shift;;
|
||||
--keep-dlock) opt_keepdlock=1; shift;;
|
||||
--overwrite) opt_overwrite=1; shift;;
|
||||
--syslog) opt_syslog=1; shift;;
|
||||
--) shift; break;;
|
||||
*) break;;
|
||||
esac
|
||||
@@ -181,7 +188,7 @@ function parse_opts(){
|
||||
log info "============================================"
|
||||
log info "Proxmox VE Version:"
|
||||
|
||||
echowhite $(pveversion)
|
||||
echowhite "$(pveversion)"
|
||||
|
||||
log info "============================================"
|
||||
fi
|
||||
@@ -339,6 +346,7 @@ function log(){
|
||||
local level=$1
|
||||
shift 1
|
||||
local message=$*
|
||||
local syslog_msg=''
|
||||
|
||||
case $level in
|
||||
debug)
|
||||
@@ -350,28 +358,32 @@ function log(){
|
||||
|
||||
info)
|
||||
echo -e "$message";
|
||||
echo -e "$message" >> "$LOG_FILE";
|
||||
[ $opt_syslog -eq 1 ] && logger -t "$PROGNAME" "$message"
|
||||
echo -e "$message" | sed -e 's/\x1b\[[0-9;]*m//g' >> "$LOG_FILE";
|
||||
syslog_msg=$(echo -e "$message" | sed -e ${restripansicolor})
|
||||
[ $opt_syslog -eq 1 ] && logger -t "$PROGNAME" "$syslog_msg"
|
||||
;;
|
||||
|
||||
warn)
|
||||
echo -n $(echoyellow "WARNING: ")
|
||||
echo $(echowhite "$message") 1>&2
|
||||
echo -e "$message" >> "$LOG_FILE";
|
||||
[ $opt_syslog -eq 1 ] && logger -t "$PROGNAME" -p daemon.warn "$message"
|
||||
echo -n "$(echoyellow 'WARNING: ')"
|
||||
echowhite "$message" 1>&2
|
||||
echo -e "$message" | sed -e ${restripansicolor} >> "$LOG_FILE";
|
||||
syslog_msg=$(echo -e "$message" | sed -e ${restripansicolor})
|
||||
[ $opt_syslog -eq 1 ] && logger -t "$PROGNAME" -p daemon.warn "$syslog_msg"
|
||||
;;
|
||||
|
||||
error)
|
||||
echo -n $(echored "ERROR: ")
|
||||
echo $(echowhite "$message") 1>&2
|
||||
echo -e "$message" >> "$LOG_FILE";
|
||||
[ $opt_syslog -eq 1 ] && logger -t "$PROGNAME" -p daemon.err "$message"
|
||||
echo -n "$(echored 'ERROR: ')"
|
||||
echowhite "$message" 1>&2
|
||||
echo -e "$message" | sed -e ${restripansicolor} >> "$LOG_FILE";
|
||||
syslog_msg=$(echo -e "$message" | sed -e ${restripansicolor})
|
||||
[ $opt_syslog -eq 1 ] && logger -t "$PROGNAME" -p daemon.err "$syslog_msg"
|
||||
;;
|
||||
|
||||
*)
|
||||
echo "$message" 1>&2
|
||||
echo -e "$message" >> "$LOG_FILE";
|
||||
[ $opt_syslog -eq 1 ] && logger -t "$PROGNAME" "$message"
|
||||
echo -e "$message" | sed -e ${restripansicolor} >> "$LOG_FILE";
|
||||
syslog_msg=$(echo -e "$message" | sed -e ${restripansicolor})
|
||||
[ $opt_syslog -eq 1 ] && logger -t "$PROGNAME" "$syslog_msg"
|
||||
;;
|
||||
esac
|
||||
}
|
||||
@@ -427,13 +439,11 @@ function mirror() {
|
||||
end_process 1
|
||||
fi
|
||||
|
||||
|
||||
|
||||
map_source_to_destination_vmid
|
||||
map_vmids_to_host
|
||||
map_vmids_to_dsthost "$opt_destination"
|
||||
|
||||
if [ $(check_pool_exist "$opt_pool") -eq 0 ]; then
|
||||
if [ "$(check_pool_exist "$opt_pool")" -eq 0 ]; then
|
||||
log error "Preflight check: Destination RBD-Pool $opt_pool does not exist."
|
||||
end_process 255
|
||||
fi
|
||||
@@ -447,10 +457,10 @@ function mirror() {
|
||||
vmname=$(cat $PVE_NODES/"${pvnode[$vm_id]}"/$QEMU/"$vm_id".conf | sed -e ''$restripsnapshots'' | grep "name\:" | cut -d' ' -f 2)
|
||||
log info "VM $vm_id - Starting mirror for $(echowhite "$vmname")"
|
||||
srcvmgenid=$(cat $PVE_NODES/"${pvnode[$vm_id]}"/$QEMU/"$vm_id".conf | sed -e ''$restripsnapshots'' | grep vmgenid | sed -r -e 's/^vmgenid:\s(.*)/\1/')
|
||||
dstvmgenid=$(ssh $opt_destination cat $PVE_NODES/"${dstpvnode[$dvmid]}"/$QEMU/"$dvmid".conf 2>/dev/null | grep vmgenid | sed -e ''$restripsnapshots'' | sed -r -e 's/^vmgenid:\s(.*)/\1/')
|
||||
dstvmgenid=$(ssh "$opt_destination" cat $PVE_NODES/"${dstpvnode[$dvmid]}"/$QEMU/"$dvmid".conf 2>/dev/null | grep vmgenid | sed -e ''$restripsnapshots'' | sed -r -e 's/^vmgenid:\s(.*)/\1/')
|
||||
log info "VM $vm_id - Checking for VM $dvmid on destination cluster $opt_destination $QEMU_CONF_CLUSTER"
|
||||
log debug "DVMID:$dvmid srcvmgenid:$srcvmgenid dstvmgenid:$dstvmgenid"
|
||||
conf_on_destination=$(ssh $opt_destination "ls -d $QEMU_CONF_CLUSTER/$dvmid$EXT_CONF 2>/dev/null")
|
||||
conf_on_destination=$(ssh "$opt_destination" "ls -d $QEMU_CONF_CLUSTER/$dvmid$EXT_CONF 2>/dev/null")
|
||||
[[ "$conf_on_destination" =~ $redstconf ]]
|
||||
host_on_destination=${BASH_REMATCH[1]}
|
||||
|
||||
@@ -490,9 +500,9 @@ function mirror() {
|
||||
|
||||
#Lock on source + destination
|
||||
if [ $opt_lock -eq 1 ]; then
|
||||
do_run "ssh root@"${pvnode[$vm_id]}" qm set "$vm_id" --lock backup" >/dev/null
|
||||
do_run "ssh root@""${pvnode[$vm_id]}"" qm set ""$vm_id"" --lock backup" >/dev/null
|
||||
log info "VM $vm_id - locked $vm_id [rc:$?] on source"
|
||||
do_run "ssh root@"${dstpvnode[$dvmid]}" qm set "$dvmid" --lock backup" >/dev/null
|
||||
do_run "ssh root@""${dstpvnode[$dvmid]}"" qm set ""$dvmid"" --lock backup" >/dev/null
|
||||
log info "VM $dvmid - locked $dvmid [rc:$?] on destination"
|
||||
fi
|
||||
#Freeze fs only if no migration running
|
||||
@@ -500,7 +510,7 @@ function mirror() {
|
||||
vm_freeze "$vm_id" "${pvnode[$vm_id]}" >/dev/null
|
||||
freezerc=$?
|
||||
if [ $freezerc -gt 0 ]; then
|
||||
log error "VM $vm_id - QEMU-Guest could not fsfreeze on guest."
|
||||
log warn "VM $vm_id - QEMU-Guest could not fsfreeze on guest."
|
||||
(( perf_freeze_failed++ ))
|
||||
else
|
||||
(( perf_freeze_ok++ ))
|
||||
@@ -511,7 +521,7 @@ function mirror() {
|
||||
create_snapshot "$src_image_spec@$opt_snapshot_prefix$timestamp" 2>/dev/null
|
||||
ssrc=$?
|
||||
if [ $ssrc -gt 0 ]; then
|
||||
log error "VM $vm_id - rbd snap failed."
|
||||
log warn "VM $vm_id - rbd snap failed."
|
||||
(( perf_ss_failed++ ))
|
||||
else
|
||||
(( perf_ss_ok++ ))
|
||||
@@ -629,7 +639,7 @@ function mirror() {
|
||||
#--migrate so start on destination?
|
||||
if [ $opt_migrate -eq 1 ]; then
|
||||
log info "VM $dvmid - Starting VM on ${pvnode[$vm_id]}"
|
||||
do_run "ssh root@"${dstpvnode[$dvmid]}" qm start "$dvmid >/dev/null
|
||||
do_run "ssh root@""${dstpvnode[$dvmid]}"" qm start "$dvmid >/dev/null
|
||||
fi
|
||||
|
||||
done
|
||||
@@ -654,6 +664,8 @@ function mirror() {
|
||||
cmd="curl --request POST \"$opt_influx_api_url/v2/write?org=$opt_influx_api_org&bucket=$opt_influx_bucket&precision=ns\" --header \"Authorization: Token $opt_influx_token\" --header \"Content-Type: text/plain; charset=utf-8\" --header \"Accept: application/json\" --data-binary '$influxlp'"
|
||||
do_run "$cmd"
|
||||
fi
|
||||
(( perf_vm_ok++ ))
|
||||
end_process 0
|
||||
}
|
||||
|
||||
function do_housekeeping(){
|
||||
@@ -782,23 +794,25 @@ function do_run(){
|
||||
|
||||
function end_process(){
|
||||
local -i rc=$1;
|
||||
# if ! [[ -z "$startts" && -z "$endts" ]]; then
|
||||
# local -i runtime=$(expr $endts - $startts)
|
||||
# local -i bps=$(expr $bytecount/$runtime)
|
||||
# fi
|
||||
# local subject="Ceph [VM:$vmok/$vmtotal SS:$snapshotok/$snapshottotal EX:$exportok/$exporttotal] [$(bytesToHuman "$bytecount")@$(bytesToHuman "$bps")/s]"
|
||||
# [ $rc != 0 ] && subject="$subject [ERROR]"
|
||||
local -i runtime
|
||||
local -i bps
|
||||
local -i ss_total
|
||||
local subject
|
||||
if ! [[ -z "$startjob" && -z "$endjob" ]]; then
|
||||
runtime=$(expr $endjob - $startjob)
|
||||
bps=$(expr $perf_bytes_total/$runtime)
|
||||
fi
|
||||
ss_total=$(expr $perf_ss_ok + $perf_ss_failed)
|
||||
subject="Crossover [VM:$perf_vm_ok/$vmcount SS:$perf_ss_ok/$ss_total]"
|
||||
[ $rc != 0 ] && subject="[ERROR] $subject" || subject="[OK] $subject"
|
||||
|
||||
#send email
|
||||
# local mail;
|
||||
# local mailhead="Backup $imgcount Images in $vmcount VMs (Bytes: $bytecount)"
|
||||
# for mail in $(echo "$opt_addr_mail" | tr "," "\n"); do
|
||||
# do_run "cat '$LOG_FILE' | mail -s '$subject' '$mail'"
|
||||
# done
|
||||
local mail;
|
||||
for mail in $(echo "$opt_addr_mail" | tr "," "\n"); do
|
||||
do_run "cat '$LOG_FILE' | mail -s '$subject' '$mail'"
|
||||
done
|
||||
|
||||
#remove log
|
||||
# rm "$LOG_FILE"
|
||||
|
||||
rm "$LOG_FILE"
|
||||
exit "$rc";
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user