From dc2786ff4d4cfc3a9a780451ef2a559e296c05a3 Mon Sep 17 00:00:00 2001 From: Simon Rettberg Date: Thu, 2 May 2024 15:37:46 +0200 Subject: [run-virt] Add support for CoW-Mode --- .../run-virt-includes/download_vm_metadata.inc | 42 ++++++++++++++++- .../run-virt-includes/get_xml_file_variables.inc | 19 +------- .../run-virt-includes/setup_image_access.inc | 52 +++++++++++++++++----- .../data/opt/openslx/vmchooser/vmchooser-run_virt | 37 +++++++++++++-- 4 files changed, 117 insertions(+), 33 deletions(-) diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/download_vm_metadata.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/download_vm_metadata.inc index a35d328b..b18b8a66 100644 --- a/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/download_vm_metadata.inc +++ b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/download_vm_metadata.inc @@ -32,23 +32,63 @@ Die Metadaten der Lehrumgebung konnten nicht umkopiert werden. Wenden Sie sich an den Support, wenn das Problem bestehen bleibt. $EXTRA_ERROR" cleanexit 1 fi + if [ -s "$CONFDIR/config.inc" ]; then + $( safesource "$CONFDIR/config.inc" ) + notempty DMSD_IMAGE_PATH && SRC_IMG_RELATIVE="$DMSD_IMAGE_PATH" + fi + + # Validate metadata from XML, now that it has potentially been augmented + readonly SRC_IMG_RELATIVE + + if isempty SRC_IMG_ABSOLUTE SRC_IMG_RELATIVE; then + writelog "Error parsing XML: Neither relative nor absolute path for image found!" + EXIT_TYPE="user" EXIT_REASON="Konnte keinen Pfad zur ausgewählten virtuellen Maschine ermitteln!" cleanexit 1 + fi + + if isempty SRC_IMG_ABSOLUTE && notempty VMSTORE_PATH; then + SRC_IMG_ABSOLUTE="${VMSTORE_PATH}/${SRC_IMG_RELATIVE}" + fi + readonly SRC_IMG_ABSOLUTE + + declare -rg IMG_BASENAME=$(basename "$SRC_IMG_ABSOLUTE") + + notempty VM_DISPLAYNAME || VM_DISPLAYNAME="${IMG_BASENAME}" + readonly VM_DISPLAYNAME + + # Define VM_CLEANNAME since VM_DISPLAYNAME can be long and contain weird characters + declare -rg VM_CLEANNAME=$(echo "${VM_DISPLAYNAME:0:32}" | sed -r 's/[^0-9a-zA-Z_\-\.]+/_/g') + + # return 0 } download_metadata_default() { local TRIES WLOG TMPFILE RET ERRCODE CMDLINE + local cow_token argx # Sanity checks if ! check_dep curl; then writelog "Could not find 'curl' in PATH: $PATH" EXIT_TYPE="internal" EXIT_REASON="Fehlendes Dienstprogramm 'curl'!" cleanexit 1 fi + # Admin-mode (Edit-Mode) + argx= + if is_on "$VMCHOOSER_ADMIN_MODE"; then + cow_token=$( cat "/run/user/$( id -u )/cow-token" ) + if isempty cow_token; then + writelog "No cow token found in edit mode" + EXIT_TYPE=user EXIT_REASON="Admin-Modus aktiviert, aber kein cow-token vorgefunden." cleanexit 1 + fi + argx="?cow-user=$cow_token" + fi + # Try new unified .tar.gz way TMPFILE="$TMPDIR/metadata.tgz" WLOG="$TMPDIR/curl-metadata.log" CMDLINE= curl --help | grep -q -- --retry-connrefused && CMDLINE="--retry-connrefused" - curl -L -o "$TMPFILE" -w '\nretval:%{http_code}\n' --retry 3 $CMDLINE --max-time 8 --retry-max-time 15 "${url_lecture_metadata}" &> "$WLOG" + curl -L -o "$TMPFILE" -w '\nretval:%{http_code}\n' --retry 3 $CMDLINE --max-time 8 --retry-max-time 15 \ + "${url_lecture_metadata}${argx}" &> "$WLOG" ERRCODE=$( awk -F: '{ if ($1 == "retval") print $2 }' "$WLOG" ) RET=$? if [ "$RET" = 0 ] && [ -n "$ERRCODE" ] && [ "$ERRCODE" -ge 200 ] && [ "$ERRCODE" -lt 300 ]; then diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/get_xml_file_variables.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/get_xml_file_variables.inc index b4ab4c1c..17f0e8ed 100644 --- a/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/get_xml_file_variables.inc +++ b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/get_xml_file_variables.inc @@ -24,32 +24,15 @@ parse_xml() { [ -n "$url_lecture_runscript" ] && readonly url_lecture_runscript="${url_lecture_runscript//%UUID%/${IMGUUID}}" # Relative / Absolute path to image - declare -rg SRC_IMG_RELATIVE=$(get_xml "image_name") + declare -g SRC_IMG_RELATIVE=$(get_xml "image_name") declare -g SRC_IMG_ABSOLUTE=$(get_xml "image_path") - if isempty SRC_IMG_ABSOLUTE SRC_IMG_RELATIVE; then - writelog "Error parsing XML: Neither relative nor absolute path for image found!" - EXIT_TYPE="user" EXIT_REASON="Konnte kein Pfad zur ausgewählten virtuellen Maschine ermitteln!" cleanexit 1 - fi - if notempty SRC_IMG_ABSOLUTE && [ "${SRC_IMG_ABSOLUTE:0:1}" != "/" ]; then writelog "Error parsing XML: Parsed value for absolute path doesn't start with '/': '$SRC_IMG_ABSOLUTE'" EXIT_TYPE="user" EXIT_REASON="Ungültiger asboluter Pfad zur virtuellen Maschine!" cleanexit 1 fi - if isempty SRC_IMG_ABSOLUTE && notempty VMSTORE_PATH; then - SRC_IMG_ABSOLUTE="${VMSTORE_PATH}/${SRC_IMG_RELATIVE}" - fi - readonly SRC_IMG_ABSOLUTE - - declare -rg IMG_BASENAME=$(basename "$SRC_IMG_ABSOLUTE") - VM_DISPLAYNAME=$(get_xml "short_description") - notempty VM_DISPLAYNAME || VM_DISPLAYNAME="${IMG_BASENAME}" - readonly VM_DISPLAYNAME - - # Define VM_CLEANNAME since VM_DISPLAYNAME can be long and contain weird characters - declare -rg VM_CLEANNAME=$(echo "${VM_DISPLAYNAME:0:32}" | sed -r 's/[^0-9a-zA-Z_\-\.]+/_/g') # image is for the following virtual machine declare -rg PLUGIN_ID=$(get_xml "virtualmachine") diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_image_access.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_image_access.inc index 8b166806..5b0786c8 100644 --- a/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_image_access.inc +++ b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/setup_image_access.inc @@ -40,34 +40,66 @@ setup_dnbd3_proxy () { } setup_dnbd3 () { + local dnbd3_tmplog="${TMPDIR}/dnbd3fuse.log" + local dnbd3_diskfile= + setup_dnbd3_common + + if isempty dnbd3_diskfile; then + slxlog "virt-dnbd3" "No dnbd3 server for ${SRC_IMG_RELATIVE} found, trying NFS/CIFS..." "$dnbd3_tmplog" + writelog "No working dnbd3 server found :-(" + return 1 + fi + VM_DISKFILE_RO="$dnbd3_diskfile" + return 0 +} + +setup_dnbd3_cow () { + local dnbd3_tmplog="${TMPDIR}/dnbd3fuse.log" + local dnbd3_diskfile= + + mkdir "${TMPDIR}/cow" + setup_dnbd3_common -L "${TMPDIR}/cow" -C "${SLX_VMCHOOSER_BASE_URL//"/vmchooser/"/"/cow/"}" --upload-uuid "$DMSD_COW_SESSION" --cow-stats-file --merge + + if isempty dnbd3_diskfile; then + slxlog "virt-dnbd3" "Failed to setup dnbd3-fuse with copy-on-write" "$dnbd3_tmplog" + writelog "Error setting up CoW" + cleanexit 1 + fi + VM_DISKFILE_RW="$dnbd3_diskfile" +} + +setup_dnbd3_common () { # Mount path for images mounted with dnbd3-fuse declare -rg DNBD3_MOUNT_POINT="${TMPDIR}/dnbd3fuse.mnt" mkdir -p "${DNBD3_MOUNT_POINT}" # start dnbd3-fuse in subshell - local DNBD3_TMPLOG="${TMPDIR}/dnbd3fuse.log" local DNBD3_EXITFLAG="${TMPDIR}/dnbd3exit$RANDOM" local TIMEOUT VM_DISKFILE_REVISION rm -f -- "${DNBD3_EXITFLAG}" ( + trap 'kill $dnbd3pid; exit' SIGTERM startup="$( date +%s )" while [ "$( date +%s )" -lt "$(( startup + 4 ))" ]; do - dnbd3-fuse -f -o allow_other,max_readahead=262144 -h "${SLX_DNBD3_SERVERS}" -i "${SRC_IMG_RELATIVE}" "${DNBD3_MOUNT_POINT}" > "${DNBD3_TMPLOG}" 2>&1 + dnbd3-fuse -f -o allow_other,max_readahead=262144 -h "${SLX_DNBD3_SERVERS}" -i "${SRC_IMG_RELATIVE}" "$@" "${DNBD3_MOUNT_POINT}" &> "${dnbd3_tmplog}" & + dnbd3pid=$! + wait "$dnbd3pid" RET=$? done touch "${DNBD3_EXITFLAG}" if [ "$RET" != "0" ]; then writelog "dnbd3-fuse stopped working (Exit code $RET)" - slxlog "virt-dnbd3-fuse" "dnbd3-fuse stopped/refused serving '${SRC_IMG_RELATIVE}' from '${SLX_DNBD3_SERVERS}' with error code: $RET" "${DNBD3_TMPLOG}" + slxlog "virt-dnbd3-fuse" "dnbd3-fuse stopped/refused serving '${SRC_IMG_RELATIVE}' from '${SLX_DNBD3_SERVERS}' with error code: $RET" "${dnbd3_tmplog}" fi ) & + declare -rg DNBD3_PID=$! # give it a bit of time usleep 250000 # check if we have the image for TIMEOUT in 0.5 1 1 1 1 2 OUT; do if [ -r "${DNBD3_MOUNT_POINT}/img" ]; then VM_DISKFILE_REVISION="$(grep -m 1 "^Revision:" "${DNBD3_MOUNT_POINT}/status" | cut -d" " -f2)" - VM_DISKFILE_RO="${DNBD3_MOUNT_POINT}/img" - writelog "DNBD3: ${SRC_IMG_RELATIVE} on ${VM_DISKFILE_RO} with rid ${VM_DISKFILE_REVISION}" + dnbd3_diskfile="${DNBD3_MOUNT_POINT}/img" + writelog "DNBD3: ${SRC_IMG_RELATIVE} on ${dnbd3_diskfile} with rid ${VM_DISKFILE_REVISION}" add_cleanup "cleanup_dnbd3" break fi @@ -76,11 +108,6 @@ setup_dnbd3 () { fi sleep "$TIMEOUT" done - - if isempty VM_DISKFILE_RO; then - slxlog "virt-dnbd3" "No dnbd3 server for ${SRC_IMG_RELATIVE} found, trying NFS/CIFS..." "$DNBD3_TMPLOG" - writelog "No working dnbd3 server found :-(" - fi } setup_fallback() { @@ -143,6 +170,9 @@ setup_image_access_default() { writelog "\tCan't use dnbd3 as SRC_IMG_RELATIVE is not set" elif isempty SLX_DNBD3_SERVERS || [ "x${SLX_VM_DNBD3}" != "xyes" ]; then writelog "\tCan't use dnbd3 as no servers are given in config, or SLX_VM_DNBD3 is not set to yes" + elif [ -n "$DMSD_COW_SESSION" ]; then + writelog "Setting up DNBD3 CoW session" + setup_dnbd3_cow elif setup_dnbd3_proxy; then writelog "\tImage setup done." elif ! check_dep dnbd3-fuse fusermount; then @@ -152,7 +182,7 @@ setup_image_access_default() { writelog "Trying image access via DNBD3..." setup_dnbd3 fi - + # VM_DISKFILE_RO will be empty if dnbd3 is not used or failed to connect. if isempty VM_DISKFILE_RO; then # try to fallback to access the image via NFS/CIFS filesystem diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/vmchooser-run_virt b/core/modules/run-virt/data/opt/openslx/vmchooser/vmchooser-run_virt index ca881f29..dfebebe7 100755 --- a/core/modules/run-virt/data/opt/openslx/vmchooser/vmchooser-run_virt +++ b/core/modules/run-virt/data/opt/openslx/vmchooser/vmchooser-run_virt @@ -182,14 +182,45 @@ main() { run_hooks "pre-exec" "$PLUGIN_ID" "$IMGUUID" + # Launch COWGUI in CoW-Edit-Mode + local cowpid cowurl vmpidfile + cowpid= + vmpidfile= + if [ -n "$DMSD_COW_SESSION" ]; then + vmpidfile="$( mktemp -p "/run/user/$( id -u )" )" + cowurl="${SLX_VMCHOOSER_BASE_URL//"/vmchooser/"/"/cow/"}" + ( + cntr=0 + while true; do + cowgui --session "$DMSD_COW_SESSION" --url "$cowurl" --pid "$DNBD3_PID" && break + # Unclean exit, let's see if it's worth relaunching + state="$( curl -m 3 -sS -L "$cowurl/status/$DMSD_COW_SESSION" | jq -r .state )" + [ -z "$state" ] && break + [ "$state" = "PROCESSING" ] && break + [ "$state" = "ERROR" ] && break + [ "$state" = "COMPLETELY_DONE" ] && break + (( cntr++ > 10 )) && break + done + [ -n "$vmpidfile" ] && kill "$( cat "$vmpidfile" )" + ) & + cowpid=$! + fi + writelog "VM command: ${VIRTCMD} ${VIRTCMDOPTS[*]}" - # This will start the VM (no eval needed!) + # This will start the VM writelog "---------- BEGIN VM command output ----------" - local retval - "${VIRTCMD}" "${VIRTCMDOPTS[@]}" &>> "${LOGFILE}" + local retval vmpid + "${VIRTCMD}" "${VIRTCMDOPTS[@]}" &>> "${LOGFILE}" & + vmpid=$! + [ -n "$vmpidfile" ] && echo "$vmpid" > "$vmpidfile" + wait "$vmpid" retval=${?} writelog "---------- END VM command output ----------" + [ -n "$DNBD3_PID" ] && kill "$DNBD3_PID" + # If cow, wait for GUI + [ -n "$cowpid" ] && wait "$cowpid" + run_hooks "post-exec" "$PLUGIN_ID" "$IMGUUID" writelog "Virtualizer exited with '$retval'. Bye." -- cgit v1.2.3-55-g7522