#!/bin/bash # Full bash required # ----------------------------------------------------------------------------- # # Copyright (c) 2007..2018 bwLehrpool-Projektteam # # This program/file is free software distributed under the GPL version 2. # See https://www.gnu.org/licenses/old-licenses/gpl-2.0-standalone.html # # If you have any feedback please consult https://bwlehrpool.de and # send your feedback to support@bwlehrpool.de. # # General information about bwLehrpool can be found at https://bwlehrpool.de # # ----------------------------------------------------------------------------- # run-virt.sh # - This is the generic wrapper for the several virtualization solutions. # The idea is to setup a set of variables used by at least two different # tools and then include the specific plugin which configures the speci- # fied virtualization tool. ################################################################################ SELF="$( readlink -f "${BASH_SOURCE[0]}" )" if [ -z "$SELF" ] || ! [ -f "$SELF" ]; then SELF="$( readlink -f "$0" )" fi if [ -z "$SELF" ] || ! [ -f "$SELF" ]; then slxlog "run-virt" "Cannot find SELF" exit 1 fi readonly SELF # Global variables needed for the core functionality declare -rg VMCHOOSER_DIR="$( dirname "$SELF" )" declare -rg VMCHOOSER_CONF_DIR="$VMCHOOSER_DIR/config" declare -rg USER="$(whoami)" declare -rg TMPDIR="/tmp/virt/${USER}/$$" declare -rg CONFDIR="${TMPDIR}/metadata" if ! [ -d "$VMCHOOSER_DIR" ]; then slxlog "run-virt" "$SELF is not in a directory!?" exit 1 fi # Useless without this . /opt/openslx/config . /opt/openslx/bin/slx-tools # Debug mode? if [ "$1" = "--debug" ]; then shift DEBUG=true elif is_debug; then DEBUG=true else DEBUG=false fi readonly DEBUG # Check for existence of plugin if [ "x$1" = "x--query" ]; then PLUGIN_ID="${2//[^a-z_\-]/}" if [ -z "$PLUGIN_ID" ]; then echo "Error: No plugin name given" >&2 exit 1 fi if ! [ -f "$VMCHOOSER_DIR/plugins/$PLUGIN_ID/run-virt.include" ]; then echo "Plugin '$PLUGIN_ID' does not exist." >&2 exit 1 fi # Maybe in the future we want to output information about the plugin here # to stdout in a simple to parse format like key=value.... echo "Plugin '$PLUGIN_ID' found" >&2 exit 0 fi # This script expects the path to the xml file describing the VM to be started declare -rg XML_FILE="$1" # A path to the logfile can be given as second argument declare -g LOGFILE="$2" if [ -z "$LOGFILE" ] || ! touch "$LOGFILE" || ! [ -f "$LOGFILE" ]; then LOGFILE="/var/log/openslx/run-virt.${USER}.$$.log" touch "$LOGFILE" || LOGFILE="$(mktemp)" fi readonly LOGFILE main() { declare -rg MAINPID="$BASHPID" # Don't have writelog yet echo "MAINPID: $MAINPID" # Functions needed by vmchooser-run_virt (writelog(), cleanexit(), safesource()) declare -rg RUN_VIRT_INCLUDE_DIR="${VMCHOOSER_DIR}/run-virt-includes" if ! source "${RUN_VIRT_INCLUDE_DIR}/vmchooser_runvirt_functions.inc"; then slxlog "run-virt" "Could not source ${RUN_VIRT_INCLUDE_DIR}/vmchooser_runvirt_functions.inc" exit 1 fi trap 'cleanexit $?' EXIT trap 'cleanexit 129' SIGHUP trap 'cleanexit 130' SIGINT trap 'cleanexit 143' SIGTERM # Starting sourcing the includes files. Note that the critical ones should use # the '--exit' option of safesource to trigger cleanexit in case of a corrupted/bad # include file. # Set core runvirt variables and directories $(safesource --exit "${RUN_VIRT_INCLUDE_DIR}/init_core.inc") writelog "#################### Initialization ####################" # Read vmchooser.conf, (generated) virtualization.conf and slx config files $(safesource --exit "${RUN_VIRT_INCLUDE_DIR}/load_configs.inc") # Declaration of hardware related variables $(safesource --exit "${RUN_VIRT_INCLUDE_DIR}/set_runvirt_hardware_variables.inc") # Window manager required early for user feedback through popups (e.g. errors) etc. $(safesource "${RUN_VIRT_INCLUDE_DIR}/start_windowmanager.inc") # Read needed variables from XML file $(safesource --exit "${RUN_VIRT_INCLUDE_DIR}/get_xml_file_variables.inc") # Download metadata from server (e.g. vmx for vmware) $(safesource --exit "${RUN_VIRT_INCLUDE_DIR}/download_vm_metadata.inc") # Try to use dnbd3 to access the image, nfs/cifs fallback $(safesource --exit "${RUN_VIRT_INCLUDE_DIR}/setup_image_access.inc") # Mark the end of generic run-virt part writelog "Done with generic run-virt. Now loading virtualizer-specific includes." writelog "#################### Plugin init: $PLUGIN_ID ####################" # NG: first include the hypervisor includes $(safesource "${RUN_VIRT_INCLUDE_DIR}/setup_vm_hypervisor.inc") # It must declare PLUGIN_FEATURES to set which features are needed. # Features are those defined by run-virt.d include files. # After sourcing the plugin, check that it defined both PLUGIN_FEATURES and # the main function 'run_plugin' which will be called later by the main scripts. if ! isset PLUGIN_FEATURES || ! is_function run_plugin; then writelog "Bad plugin '$PLUGIN_ID': either it did not set PLUGIN_FEATURES or did not define 'run_plugin'." EXIT_TYPE="internal" EXIT_REASON="Fehlerhaftes vmchooser plugin: '$PLUGIN_ID'." cleanexit 1 fi writelog "Requested features:\t${PLUGIN_FEATURES}" # Source the *.inc files in run-virt.d for FILE in ${VMCHOOSER_DIR}/run-virt.d/*.inc; do $(safesource "$FILE") done # Now look which features were requested and call the handler if one is defined. for FEAT in $PLUGIN_FEATURES; do if notempty FEATURE_HANDLERS["${FEAT}"]; then writelog "Initialising '${FEAT}'..." if ! ${FEATURE_HANDLERS["$FEAT"]}; then writelog "\tFailed to run '${FEATURE_HANDLERS["$FEAT"]}'." error_user "Konnte Feature namens '$FEAT' nicht initialisieren! Diese Funktion wird nicht verfügbar sein!" # not critical, do not exit! fi else writelog "\tFeature '$FEAT' has no handler! This function will be unavailable." notify_user "Feature '$FEAT' nicht unterstützt" fi done # Prepare array for the command line options unset VIRTCMDOPTS declare -a VIRTCMDOPTS # The features should now be initialized, call the main 'run_plugin' function of the hypervisor writelog "#################### Plugin run: $PLUGIN_ID ####################" writelog "Calling 'run_plugin' of '$PLUGIN_ID'..." run_plugin || writelog "Failed to run 'run_plugin' of '$PLUGIN_ID'." # It should have set this variable if all went well if isempty VIRTCMD; then error_user "Fehler beim Starten der VM-Sitzung" " Das Start-Script für den Virtualisierer $PLUGIN_ID hat kein Kommando zum Starten der Sitzung definiert. Kann Sitzung nicht initialisieren." slxlog "virt-plugin-error" "run-virt.include for $PLUGIN_ID did not set VIRTCMD" cleanexit 1 fi 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 writelog "---------- BEGIN VM command output ----------" 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." cleanexit 0 } # Detach main & RUNVIRT_PID="$!" # Give some time usleep 100000 if ! kill -0 "${RUNVIRT_PID}"; then if [ -n "${LOGFILE}" ] && [ -f "${LOGFILE}" ]; then echo "Failed to start runvirt main function. Seems that it exited early (<100ms)." >> "${LOGFILE}" fi fi wait "$RUNVIRT_PID" RUNVIRT_RET="$?" if [ "${RUNVIRT_RET}" -ne 0 ]; then if [ "${RUNVIRT_RET}" -eq 141 ]; then # 141 happens on alt + print screen + k or upon automatic logout via systemd # just sleep here to avoid these annoying (and misleading) slxlogs.... sleep 2 ; sleep 2 fi [ -s "${LOGFILE}" ] && slxlog "run-virt-wrapper" "Failed to launch runvirt!" "${LOGFILE}" exit "$RUNVIRT_RET" fi exit 0