
- The new virtiofsd provides the ability to map a specified UID and GID to that of the user when running in user mode. As a result, virtiofsd is moved to userland for VMs and the new -uid and -gid options are introduced that specify the IDs on the guest.New v - The drives no longer have to be mounted with the group ID 1010. Therefore, the mount options are changed to the real group ID
301 lines
10 KiB
Bash
Executable file
301 lines
10 KiB
Bash
Executable file
#!/usr/bin/bash
|
|
# create and run clone
|
|
|
|
set -eu
|
|
|
|
show_help() {
|
|
cat << EOF >&2
|
|
Usage: $(basename "$0") [options] vmname"
|
|
Create a new clone, start the vm (if not yet running) and run virt-viewer.
|
|
Squid-Proxy will be started too.
|
|
options:
|
|
-n|--new new clone will be created, even if exists
|
|
-p|--persistent new clone will be created persistent, so available after reboot too
|
|
-s|--system qemu:///system instead of default qemu:///session
|
|
--no-viewer start without viewer
|
|
--heads n number of displays
|
|
--memory sizeMB memory size in MB
|
|
--cpu num number of CPUs
|
|
--os OS operating system (win10|linux|..)
|
|
--data-disk size additional data-disk
|
|
--bridge virbrX additional network interface on bridge virbrX
|
|
--uid uid set uid on guest
|
|
--gid gid set gid on guest
|
|
--macvtap additional network interface on device macvtap
|
|
--options options additional options for virt-install command
|
|
EOF
|
|
}
|
|
|
|
exit_script() {
|
|
echo "run-vm.sh ${VM_NAME} terminated by trap!" >> "/tmp/${UID}/exit-run-vm.log"
|
|
virsh --connect="${QEMU}" destroy "${VM_NAME}-clone"
|
|
trap - SIGHUP SIGINT SIGTERM # clear the trap
|
|
kill -- -$$ # Sends SIGTERM to child/sub processes
|
|
}
|
|
|
|
check_images() {
|
|
# sync vm-torrents and machine definition file
|
|
sudo -u lmnsynci /usr/local/bin/vm-sync get_file "${VM_NAME}.qcow2.torrent"
|
|
[[ -f "${VM_SYSDIR}/${VM_NAME}.qcow2" ]] && sudo -u lmnsynci /usr/local/bin/vm-sync delete_outdated_image "${VM_NAME}.qcow2"
|
|
|
|
BACKINGARRAY=()
|
|
imgfile="${VM_SYSDIR}/${VM_NAME}.qcow2" && [[ -f "${VM_DIR}/${VM_NAME}.qcow2" ]] && imgfile="${VM_DIR}/${VM_NAME}.qcow2"
|
|
BACKINGARRAY+=("${imgfile}")
|
|
echo "Imgfile=$imgfile"
|
|
if [[ ! -f "${imgfile}" ]] || ! qemu-img info -U "${imgfile}" | grep "file format: qcow2"; then
|
|
if [[ ! -f "${VM_SYSDIR}/${VM_NAME}.qcow2.torrent" ]]; then
|
|
echo "no base VM disk '${VM_NAME}.qcow2' found and/or ${VM_NAME} not found on server" >&2
|
|
exit 1
|
|
fi
|
|
# sync vm-disk image by torrent
|
|
echo "Try to sync VM ${VM_NAME} by torrent"
|
|
sudo -u lmnsynci /usr/local/bin/vm-sync get_image "${VM_NAME}"
|
|
fi
|
|
|
|
backingfile=$(qemu-img info -U "${imgfile}" | grep "^backing file:" | cut -d ' ' -f 3)
|
|
while [[ -n "${backingfile}" ]]; do
|
|
echo "Backingfile required: ${backingfile}"
|
|
imgfile="${VM_SYSDIR}/${backingfile}" && [[ -f "${VM_DIR}/${backingfile}" ]] && imgfile="${VM_DIR}/${backingfile}"
|
|
BACKINGARRAY+=("${imgfile}")
|
|
sudo -u lmnsynci /usr/local/bin/vm-sync get_file "${backingfile}.torrent"
|
|
[[ -f "${VM_SYSDIR}/${backingfile}" ]] && sudo -u lmnsynci /usr/local/bin/vm-sync delete_outdated_image "${backingfile}"
|
|
if [[ ! -f "${imgfile}" ]] || ! qemu-img info -U "${imgfile}" | grep "file format: qcow2"; then
|
|
# sync vm-disk image by torrent
|
|
echo "Try to sync backingfile ${backingfile} by torrent"
|
|
sudo -u lmnsynci /usr/local/bin/vm-sync get_image "${backingfile%.qcow2}"
|
|
fi
|
|
backingfile=$(qemu-img info -U "${imgfile}" | grep "^backing file:" | cut -d ' ' -f 3)
|
|
done
|
|
|
|
echo "VM-Image and required backingfiles available"
|
|
echo "Now, let's check the images."
|
|
|
|
# Check VM-Images in reverse order
|
|
for ((i=${#BACKINGARRAY[@]}-1; i>=0; i--))
|
|
do
|
|
echo "Checking ${BACKINGARRAY[$i]}"
|
|
if ! qemu-img check -U "${BACKINGARRAY[$i]}" 2>/dev/null; then
|
|
echo "check failed!"
|
|
echo "sync ${BACKINGARRAY[$i]} again"
|
|
sudo -u lmnsynci /usr/local/bin/vm-sync get_file "${BACKINGARRAY[$i]}.torrent"
|
|
sudo -u lmnsynci /usr/local/bin/vm-sync get_image "$(basename "${BACKINGARRAY[$i]}" .qcow2)"
|
|
fi
|
|
done
|
|
echo "VM-Image and required backingfiles available and checked"
|
|
|
|
sudo -u lmnsynci /usr/local/bin/vm-sync update_usage_information ${BACKINGARRAY[*]}
|
|
}
|
|
|
|
create_clone() {
|
|
local VM_NAME="$1"
|
|
|
|
if ! [[ -f "${VM_SYSDIR}/${VM_NAME}.qcow2" || -f "${VM_DIR}/${VM_NAME}.qcow2" ]]; then
|
|
echo "qcow2 File does not exists." >&2
|
|
exit 1
|
|
fi
|
|
|
|
# Create User-VM-Dir and link system VM-Images
|
|
[[ -d "${VM_DIR}" ]] || mkdir -p "${VM_DIR}"
|
|
if [[ "${PERSISTENT}" -eq 1 ]]; then
|
|
sudo /usr/local/bin/vm-link-images -p
|
|
else
|
|
sudo /usr/local/bin/vm-link-images
|
|
fi
|
|
|
|
# Create backing file
|
|
cd "${VM_DIR}"
|
|
qemu-img create -f qcow2 -F qcow2 -b "${VM_NAME}.qcow2" "${VM_NAME}-clone.qcow2"
|
|
|
|
}
|
|
|
|
create_printerlist() {
|
|
## Prepare .printerlist.csv
|
|
mkdir -p "${VM_MEDIADIR}"
|
|
chgrp "$(id -g)" "${VM_MEDIADIR}"
|
|
echo "Name;IppURL" > "${VM_MEDIADIR}/.printerlist.csv"
|
|
for p in $(lpstat -v | cut -f 3 -d" " | sed 's/:$//'); do
|
|
echo "$p;ipp://192.168.122.1/printers/$p" >> "${VM_MEDIADIR}/.printerlist.csv"
|
|
done
|
|
}
|
|
|
|
start_virtiofsd() {
|
|
# BEGIN temporary fix, while linux-starter are not migrated to --uid and --gid
|
|
if [[ "$LIBVIRTOSINFO" =~ "debian.*" ]]; then
|
|
GUEST_UID=1000
|
|
GUEST_GID=1010
|
|
fi
|
|
# END temporary fix
|
|
socket="/run/user/$(id -u $USER)/virtiofs-${VM_NAME}.sock"
|
|
/usr/local/bin/virtiofsd.v1.11 --uid-map=:${GUEST_UID}:${UID}:1: --gid-map=:${GUEST_GID}:$(id -g):1: \
|
|
--socket-path "$socket" --shared-dir "/lmn/media/${USER}" --syslog &
|
|
}
|
|
|
|
QEMU='qemu:///session'
|
|
|
|
NEWCLONE=0
|
|
PERSISTENT=0
|
|
LIBVIRTOSINFO="win10"
|
|
LIBVIRTOPTS=""
|
|
NO_VIEWER=0
|
|
GUEST_UID=0
|
|
GUEST_GID=0
|
|
|
|
source /etc/lmn/vm.conf
|
|
|
|
TEMP=$(getopt -o no:ps --long new,no-viewer,options:,persistent,system,memory:,data-disk:,heads:,cpu:,bridge:,macvtap,os:,uid:,gid:,help -n $0 -- "$@")
|
|
if [ $? != 0 ] ; then echo "Terminating..." >&2 ; exit 1 ; fi
|
|
|
|
eval set -- "$TEMP"
|
|
|
|
while true; do
|
|
case "$1" in
|
|
-p | --persistent )
|
|
PERSISTENT=1;
|
|
VM_DIR="${VM_DIR_PERSISTENT}"
|
|
shift
|
|
;;
|
|
-n | --new )
|
|
NEWCLONE=1
|
|
shift
|
|
;;
|
|
-s | --system )
|
|
QEMU='qemu:///system'
|
|
shift
|
|
;;
|
|
-o | --options )
|
|
LIBVIRTOPTS=$2
|
|
shift 2
|
|
;;
|
|
--no-viewer )
|
|
NO_VIEWER=1
|
|
shift
|
|
;;
|
|
--data-disk )
|
|
LIBVIRTOPTS="${LIBVIRTOPTS} --disk ${VM_DIR}/data.qcow2,size=$2,sparse=yes"
|
|
shift 2
|
|
;;
|
|
--heads )
|
|
for i in $(seq $2)
|
|
do
|
|
LIBVIRTOPTS="${LIBVIRTOPTS} --video model.heads=$i"
|
|
done
|
|
shift 2
|
|
;;
|
|
--memory )
|
|
mem_avail=$(sed -En "s/^MemAvailable:\s+([0-9]+)\s+kB/\1/p" /proc/meminfo)
|
|
mem_avail=$((mem_avail / 1024 - 2048))
|
|
if (( $2 < mem_avail )); then
|
|
LIBVIRTOPTS="${LIBVIRTOPTS} --memory $2"
|
|
else
|
|
LIBVIRTOPTS="${LIBVIRTOPTS} --memory ${mem_avail}"
|
|
fi
|
|
shift 2
|
|
;;
|
|
--cpu )
|
|
#cpu=$(sed -En "0,/^cpu cores/s/^cpu cores\s+:\s+([0-9]+)/\1/p" /proc/cpuinfo)
|
|
cpu=$(lscpu | grep "^CPU(s):" | sed 's/.* //g')
|
|
if (( $2 < cpu )); then
|
|
LIBVIRTOPTS="${LIBVIRTOPTS} --vcpu $2"
|
|
else
|
|
LIBVIRTOPTS="${LIBVIRTOPTS} --vcpu ${cpu}"
|
|
fi
|
|
shift 2
|
|
;;
|
|
--bridge )
|
|
if ip link | grep $2; then
|
|
LIBVIRTOPTS="${LIBVIRTOPTS} --network=bridge=$2,model.type=virtio"
|
|
fi
|
|
shift 2
|
|
;;
|
|
--macvtap )
|
|
for interface in $(ip link | sed -En 's/.*(macvtap-.*)@.*/\1/p'); do
|
|
mac="$(ip link | grep -A1 "${interface}" | \
|
|
sed -nE "s%\s+link/ether ([[:xdigit:]:]{17}) .+%\1%p")"
|
|
type="ethernet,mac=${mac},target.dev=${interface},xpath1.set=./target/@managed=no,model.type=virtio"
|
|
LIBVIRTOPTS="${LIBVIRTOPTS} --network type=$type"
|
|
done
|
|
shift
|
|
;;
|
|
--os )
|
|
LIBVIRTOSINFO=$2
|
|
shift 2
|
|
;;
|
|
--uid )
|
|
GUEST_UID=$2
|
|
shift 2
|
|
;;
|
|
--gid )
|
|
GUEST_GID=$2
|
|
shift 2
|
|
;;
|
|
--help )
|
|
show_help
|
|
exit 1
|
|
;;
|
|
-- ) shift; break ;;
|
|
* ) break ;;
|
|
esac
|
|
done
|
|
|
|
# if less than one arguments supplied, display usage
|
|
if [[ $# -ne 1 ]] ; then
|
|
show_help
|
|
exit 1
|
|
fi
|
|
|
|
VM_NAME=$1
|
|
|
|
# check, if we have to start squid
|
|
if ! killall -s 0 squid; then
|
|
echo "starting squid."
|
|
/usr/sbin/squid -f /etc/squid/squid-usermode.conf
|
|
fi
|
|
|
|
# because virsh has problems with long pathnames, using diffent configdir
|
|
export XDG_CONFIG_HOME="/tmp/${UID}/.config"
|
|
|
|
if ! virsh --connect="${QEMU}" list | grep "${VM_NAME}-clone"; then
|
|
echo "VM not yet running."
|
|
sudo /usr/local/bin/desktop-sync
|
|
check_images
|
|
if [[ "${NEWCLONE}" = 1 ]] || [[ ! -f "${VM_DIR}/${VM_NAME}-clone.qcow2" ]]; then
|
|
create_clone "${VM_NAME}"
|
|
fi
|
|
# delete the old vm
|
|
virsh --connect=qemu:///session undefine "${VM_NAME}-clone" || echo "${VM_NAME}-clone did not exist"
|
|
#trap exit_script SIGHUP SIGINT SIGTERM
|
|
|
|
create_printerlist
|
|
# start virtiofsd-service
|
|
[[ "${QEMU}" = 'qemu:///session' ]] && start_virtiofsd
|
|
|
|
# finally, create the new vm
|
|
|
|
virt-install \
|
|
--osinfo "${LIBVIRTOSINFO}" \
|
|
--name "${VM_NAME}-clone" \
|
|
--import \
|
|
--clock hpet_present=yes,hypervclock_present=yes \
|
|
--features hyperv.synic.state=on,xpath1.set=./hyperv/vpindex/@state=on,xpath2.set=./hyperv/stimer/@state=on \
|
|
--memorybacking source.type=memfd,access.mode=shared \
|
|
--disk "${VM_DIR}/${VM_NAME}-clone.qcow2",driver.discard=unmap,target.bus=scsi,cache=writeback \
|
|
--network=bridge=virbr0,model.type=virtio \
|
|
--filesystem driver.type=virtiofs,accessmode=passthrough,target.dir=virtiofs,xpath1.set=./source/@socket="/run/user/${UID}/virtiofs-${VM_NAME}.sock" \
|
|
--controller type=scsi,model=virtio-scsi \
|
|
--check path_in_use=off \
|
|
--connect="${QEMU}" \
|
|
--noautoconsole \
|
|
${LIBVIRTOPTS}
|
|
|
|
# --dry-run \
|
|
# --print-xml \
|
|
# > /tmp/vm.xml
|
|
# --features hyperv.synic.state=on,xpath1.set=./hyperv/vpindex/@state=on,xpath2.set=./hyperv/stimer/@state=on \
|
|
# --network type=ethernet,target.dev=vm-macvtap,xpath1.set=./target/@managed=no \
|
|
# virsh --connect="${QEMU}" start "${VM_NAME}-clone"
|
|
fi
|
|
if [[ $NO_VIEWER == 0 ]] ; then
|
|
echo "starting viewer"
|
|
trap exit_script SIGHUP SIGINT SIGTERM
|
|
virt-viewer --connect="${QEMU}" --full-screen "${VM_NAME}-clone"
|
|
fi
|