summaryrefslogtreecommitdiffstats
path: root/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/vmchooser_runvirt_functions.inc
diff options
context:
space:
mode:
authorJonathan Bauer2017-01-25 18:32:35 +0100
committerJonathan Bauer2017-01-25 18:32:35 +0100
commiteea5898961a40fc50f01356f90c42904a73a3f74 (patch)
tree52c19d11efc2d7d904ac89e36ff271de305cfc5a /core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/vmchooser_runvirt_functions.inc
parent[pam] Include cifs.upcall for DFS support (diff)
downloadmltk-eea5898961a40fc50f01356f90c42904a73a3f74.tar.gz
mltk-eea5898961a40fc50f01356f90c42904a73a3f74.tar.xz
mltk-eea5898961a40fc50f01356f90c42904a73a3f74.zip
major run-virt restructure, only vmware plugin tested!
Diffstat (limited to 'core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/vmchooser_runvirt_functions.inc')
-rw-r--r--core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/vmchooser_runvirt_functions.inc388
1 files changed, 357 insertions, 31 deletions
diff --git a/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/vmchooser_runvirt_functions.inc b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/vmchooser_runvirt_functions.inc
index ca475da0..d09f6a75 100644
--- a/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/vmchooser_runvirt_functions.inc
+++ b/core/modules/run-virt/data/opt/openslx/vmchooser/run-virt-includes/vmchooser_runvirt_functions.inc
@@ -1,8 +1,32 @@
#######################################################
# Include: Set functions needed by vmchooser-run_virt #
#######################################################
+## Assigns an ID to the currently starting VM to support
+# multiple instances running simultaneously.
+# Note that VM_ID will always have two digits.
+get_vm_id() {
+ local script=${BASH_SOURCE[-1]}
+ [ -z "$script" ] && script="$0"
+ if [ -n "$script" ]; then
+ script=$(readlink -f "$script")
+ if [ -n "$script" ] && [ -s "$script" ]; then
+ #bingo
+ declare -g VM_ID=$(ps ax | grep -F "$script" | grep -v 'grep' | grep -o -- "${script}.*\$" | sort -u | wc -l)
+ if [ "$VM_ID" -gt 0 ]; then
+ [ "${#VM_ID}" -eq 1 ] && VM_ID="0${VM_ID}"
+ [ "${#VM_ID}" -gt 2 ] && VM_ID="${VM_ID:0:2}"
+ [ "${#VM_ID}" -eq 2 ] && readonly VM_ID && return
+ fi
+ fi
+ fi
+ # fallback: take last two digits of current pid...
+ VM_ID=$(expr substr $$ $(expr ${#$} - 1) 2)
+ [ "${#VM_ID}" -eq 1 ] && VM_ID="0${VM_ID}"
+ readonly VM_ID
+}
-# function to write to stdout and logfile
+################# LOGGING FUNCTIONS ##################
+# Helper function to write to stdout and logfile
writelog() {
local DATE=$(date +%Y-%m-%d-%H-%M-%S)
# write to stdout?
@@ -12,9 +36,11 @@ writelog() {
echo -e "$DATE: $@"
fi
# log into file
- echo -e "$DATE: $@" >> "${LOGFILE}"
+ echo -e "$DATE: ${SLX_DEBUG:+(${FUNCNAME[1]}) }$@" >> "${LOGFILE}"
}
+# Helper function to notify the user.
+# This directly returns and do not wait for a user confirmation.
notify_user() {
local TOPIC="$1"
shift
@@ -22,6 +48,8 @@ notify_user() {
writelog "Notify: **${TOPIC}**: $*"
}
+# Helper to display an error message box to the user.
+# Only returns when the user dismisses the message.
error_user() {
local TOPIC="$1"
shift
@@ -37,47 +65,246 @@ $*"
BODY="$TOPIC"
fi
# Zenity should yield the nicest result
- zenity --error --title "$TITLE" --text "$BODY" && return
+ # TODO the title is only set as the window name,
+ # which cannot be seen without a window manager
+ zenity --error --title "$TITLE" --text "$BODY"
+ local RET=$?
+ [ $RET -le 1 ] && return
# QnD abuse printergui for error message as it's blocking
/opt/openslx/cups/printergui --error "$MSG" && return
# printergui might not exist, try fallback here
- # unfortunately, i can only think of notify+sleep right now
+ # unfortunately, I can only think of notify+sleep right now
notify-send -u critical "$TITLE" "$BODY"
sleep 10
}
-# Clean exit will be called at the end of vmchooser-run_virt
+################## CLEANUP FUNCTIONS ##################
+# Registers functions to be called when cleanexit is called.
+# Only accepts functions that were not previously registered.
+# This kinda detects when a cleanup function was overriden,
+# or at least that something is fishy.
+declare -ag CLEANUP_TASKS
+add_cleanup() {
+ [ $# -lt 1 ] && writelog "'${FUNCNAME[0]}' needs at least one argument! $# given." && return
+ # check if the given function name is already used
+ while [ $# -ne 0 ]; do
+ if array_contains CLEANUP_TASKS "$1"; then
+ writelog "Cleanup function '$1' already registered! Are there multiple definitions of this function?"
+ writelog "This might suggest that a previously defined cleanup function was overriden!"
+ return 1
+ fi
+ CLEANUP_TASKS+=("$1")
+ shift
+ done
+ return 0
+}
+# This function will be called at the end of vmchooser-run_virt
+# or upon critical errors during the runtime.
+# It will call the cleanup functions registered through 'add_cleanup'
+# and clean TMPDIR if appropriate. Further, it will evaluate and
+# process the EXIT_{TYPE,REASON} variables that hold information
+# on why we are about to exit.
+#
+# EXIT_TYPE should be either:
+# - 'internal' for critical internal errors, this will
+# automatically send the logfile via slxlog.
+# - 'user' for errors related to the user's choice
+# Others could be thought of like 'external' for failures
+# with remote services (e.g. slx apis, external image repo, ...)
+#
+# EXIT_REASON should contain a user-friendly message to print to the user.
cleanexit() {
+ writelog "Cleanexit '$1' triggered by '${BASH_SOURCE[1]}:${FUNCNAME[1]}'"
sleep 1
- # Ummount dnbd3-fuse
- if [ -n "$dnbd3_fuse_mount_point" ] && [ -e "$dnbd3_fuse_mount_point/img" ]; then
- for timeout in 1 1 1 FAIL; do
- fusermount -u "$dnbd3_fuse_mount_point" && break
- writelog "dnbd3 still busy...."
- [ "$timeout" = "FAIL" ] && break
- sleep "$timeout"
- done
- fi
- # Kill LPD
- [ -n "${PID_LPD}" ] && kill "${PID_LPD}"
+ while isset CLEANUP_TASKS; do
+ local TASK=${CLEANUP_TASKS[-1]}
+ unset -v CLEANUP_TASKS[-1]
+ if ! is_function $TASK; then
+ writelog "Registered cleanup function '$TASK' is not a function. This should not be..."
+ continue
+ fi
+ if ! ${TASK}; then
+ writelog "Failed to run cleanup function '$TASK'! Exit code: $RET"
+ fi
+ done
# If we're not in debug mode, remove all temporary files
- if [ -n "${TMPDIR}" -a -z "$SLX_DEBUG" ]; then
+ if notempty SLX_DEBUG && isset TMPDIR; then
rm -rf -- "${TMPDIR}"
fi
- [ $# -gt 0 ] && exit "$1"
- exit 129 # No exit code was given :/
-}
+ # Now see if we need to do the catch all error stuff
+ # no exit code given, return 129
+ [ $# -eq 0 ] && exit 129
+ # if 0 given, exit 0
+ [ "x$1" = "x0" ] && exit 0
-rv_clean_string() {
- if [ "$#" -ge 1 ]; then
- echo "$@" | tr '[A-Z]' '[a-z]' | tr -d -c '[a-z0-9\-]'
+ # given exit code is set and not 0, handle the error now
+ # now evaluate the EXIT_{TYPE,REASON} variables and generate error title/text
+ local ERR_TITLE ERR_TEXT ERR_FOOTER
+ # default error footer
+ ERR_FOOTER="Versuchen Sie den Computer neuzustarten und falls das Problem bestehen bleibt, kontaktieren Sie den Support."
+ if notempty EXIT_TYPE; then
+ case "${EXIT_TYPE}" in
+ user)
+ ERR_TITLE="Auswahlfehler"
+ ERR_FOOTER="Beim Start Ihrer Veranstaltung sind Fehler aufgetretten. Versuchen Sie es mit einer anderen Veranstaltung."
+ ;;
+ internal)
+ ERR_TITLE="Interner Fehler"
+ ;;
+ *)
+ ERR_TITLE="Unbekannter Fehler"
+ writelog "Unknown EXIT_TYPE: '${EXIT_TYPE}'."
+ ;;
+ esac
+ fi
+ if notempty EXIT_REASON; then
+ ERR_TEXT="${EXIT_REASON}"
else
- tr '[A-Z]' '[a-z]' | tr -d -c '[a-z0-9\-]'
+ # this should never happen if EXIT_REASON is properly
+ # used when calling cleanexit !
+ ERR_TEXT="Unbekannter Fehler"
+ fi
+
+ # first send the logfile (in case the user does not close the error before using magic keys e.g.)
+ # for any other error types besides 'user'.
+ [ "x${EXIT_TYPE}" != "xuser" ] && \
+ slxlog "runvirt-exit-${EXIT_TYPE}" "Critical error happened in '${BASH_SOURCE[1]}:${FUNCNAME[1]}', see logs." "${LOGFILE}"
+
+ # finally display the error
+ error_user "${ERR_TITLE}" "
+${ERR_TEXT}
+
+${ERR_FOOTER}
+"
+ writelog "All done. Exiting."
+ exit "$1"
+}
+
+################# SOURCING FUNCTIONS #################
+# Wrapped 'source' that first checks for existence and
+# syntax before actually sourcing the given file.
+# The option '--exit' triggers cleanexit upon syntax errors.
+# Without it, it returns 0 when tests passed, 1 otherwise.
+# Usage:
+# safesource [--exit] <files>
+safesource() {
+ declare -i EXIT_ON_FAILURE=0
+ [ "x$1" = "x--exit" ] && EXIT_ON_FAILURE=1 && shift
+ while [ $# -gt 0 ]; do
+ # sanitze filename just to be sure as it is part of the eval coming later
+ # alphanumeric and - _ . should be enough for common file naming scheme
+ if [[ ! "$1" =~ ^[a-zA-Z0-9./_-]+$ ]]; then
+ writelog "'$1' is a weird filename to source! Ignoring."
+ return 1
+ fi
+ local FILE="$1"
+ shift
+ bash -n "${FILE}"
+ local -i RET=$?
+ if [ $RET -ne 0 ]; then
+ case $RET in
+ 1) writelog --quiet "Bad file to source: ${FILE}" ;;
+ 2) writelog --quiet "Bad syntax: ${FILE}" ;;
+ 126) writelog --quiet "Could not access: ${FILE}" ;;
+ 127) writelog --quiet "File not found: ${FILE}" ;;
+ *) writelog --quiet "Syntax check (bash -n) returned unknown error code '${RET}' for: ${FILE}" ;;
+ esac
+ if [ $EXIT_ON_FAILURE -eq 1 ]; then
+ echo "eval EXIT_REASON=\"internal:source:${FILE}\" cleanexit 1 ;"
+ else
+ echo "eval writelog \"Could not safesource '${FILE}'.\" ;"
+ fi
+ return 1
+ fi
+ echo "eval source ${FILE} ;"
+ echo "run_post_source ${FILE} ;"
+
+ done
+ return 0
+}
+
+# Registers functions to be called after sourcing an include.
+# Includes should only define functions and register them
+# to be called after successfully sourcing.
+declare -Ag RUN_POST_SOURCE
+call_post_source() {
+ while [ $# -gt 0 ]; do
+ if ! is_function "$1"; then
+ writelog "Tried to register a non-function: '$1'"
+ continue
+ fi
+ if notempty BASH_SOURCE[1]; then
+ RUN_POST_SOURCE[${BASH_SOURCE[1]}]+="$1 "
+ shift
+ else
+ writelog "Could not determine the sourced file calling ${FUNCNAME[0]}"
+ fi
+ done
+}
+# Helper called after sourcing the file via safesource. It just calls the
+# functions in the same order they were registered.
+run_post_source() {
+ [ $# -ne 1 ] && writelog "'${FUNCNAME[0]}' expects one argument only! $# given." && return 1
+ for TASK in ${RUN_POST_SOURCE["${1}"]}; do
+ # sanity checks
+ if ! is_function $TASK; then
+ writelog "\tRegistered function '$TASK' is not a function!"
+ return 1 # TODO maybe even cleanexit here as this seems very bad...
+ fi
+ # remove from stack before running it
+ RUN_POST_SOURCE["${1}"]="${RUN_POST_SOURCE[${1//${TASK}\ /\ }]}"
+ ${TASK}
+ local -i RET=$?
+ if [ $RET -ne 0 ]; then
+ writelog "\tFailed to run post source '${TASK}' (Exit code: $RET)"
+ return $RET
+ fi
+ done
+ return 0
+}
+
+################# FEATURE FUNCTIONS ##################
+# Helper to register feature handlers, read run-virt.d/README
+declare -Ag FEATURE_HANDLERS
+reg_feature_handler() {
+ if [ $# -ne 2 ]; then
+ writelog "'${FUNCNAME[0]}' expects 2 arguments! $# given."
+ return 1
+ fi
+ if notempty FEATURE_HANDLERS["$1"]; then
+ writelog "'${BASH_SOURCE[1]}' tried to overwrite feat handler '$1'! Ignoring."
+ # maybe allow overwritting?
+ return 1
fi
+ if ! is_function "$2"; then
+ writelog "'${BASH_SOURCE[1]}' tried to register a non-function as feat handler!"
+ writelog "\t'$2' is a '$(type -t $2 2>&1)'."
+ return 1
+ fi
+ # all good, save it
+ FEATURE_HANDLERS["$1"]="$2"
+ return 0
}
+
+################### XML FUNCTIONS ####################
+# Extract given xpath from given xml file
+# e.g.: xmlextract '//node/nestednode/@attribute' "$file"
+# @param
+# @return Plain text, UTF-8
+xmlextract() {
+ xmlstarlet sel -T -E utf-8 -t -v "$1" "$2"
+}
+
+# Wrapper for convenience
+get_xml () {
+ xmlextract "//settings/eintrag/${1}/@param" "${XML_FILE}"
+}
+
+
+################## HELPER FUNCTIONS ##################
# Check if the given variables are set (empty or not)
isset() {
while [ $# -gt 0 ]; do
@@ -96,12 +323,111 @@ notempty() {
return 0
}
-##
-# Extract given xpath from given xml file
-# e.g.: xmlextract '//node/nestednode/@attribute' "$file"
-# @param
-# @return Plain text, UTF-8
-xmlextract() {
- xmlstarlet sel -T -E utf-8 -t -v "$1" "$2"
+# Convenience function
+isempty() {
+ ! notempty $@
+}
+
+# Helper to test if given arguments are declared as functions
+is_function() {
+ while [ $# -gt 0 ]; do
+ local TYPE="$(type -t "$1" 2>/dev/null)"
+ if [ "x${TYPE}" != "xfunction" ]; then
+ writelog "'$1' not a function but a '${TYPE}'."
+ return 1
+ fi
+ shift
+ done
+ return 0
}
+# Helper to test if given arguments are declared as arrays
+is_array() {
+
+ # -ne 1 ] && writelog "is_array: Expects 1 argument! $# given." && return 1
+ while [ $# -gt 0 ]; do
+ local ARRAY_DEF="$(declare -p ${1} 2>/dev/null)"
+ if [[ ! "${ARRAY_DEF}" =~ "declare -a" ]] && [[ ! "${ARRAY_DEF}" =~ "declare -A" ]]; then
+ return 1
+ fi
+ shift
+ done
+ return 0
+}
+
+# Helper to test is the given array contains given value
+# Usage:
+# array_contains ARRAY_TO_TEST <values...>
+array_contains() {
+ if [ $# -lt 2 ]; then
+ writelog "${FUNCNAME[0]}: Expects at least 2 arguments, $# given."
+ return 1
+ fi
+ # is $1 even defined?
+ local ARRAY_DEF="$(declare -p $1 2>/dev/null)"
+ if isempty ARRAY_DEF; then
+ writelog "${FUNCNAME[0]}: '$1' not defined!"
+ return 1
+ fi
+ local ARRAY_NAME="$1"
+ shift
+
+ # sanity check on $ARRAY_DEF being either indexed or associative array
+ if ! is_array "${ARRAY_NAME}"; then
+ writelog "${FUNCNAME[0]}: '${ARRAY_NAME}' not an array! Declared as:\t${ARRAY_DEF}"
+ return 1
+ fi
+
+ # now test if array contains the given values in $2+
+ while [ $# -gt 0 ]; do
+ # check if ARRAY_DEF contains '"<value>"'
+ if [[ ! "${ARRAY_DEF}" =~ '="'${1}'"'[^\]]+ ]]; then
+ writelog "${FUNCNAME[0]}: '${1}' not in '${ARRAY_NAME}'"
+ return 1
+ fi
+ shift
+ done
+ return 0
+}
+
+# Helper to check if the given arguments are valid command names.
+# This uses 'type -t' thus supports notably binaries, functions
+# and aliases (might need these one day).
+# By default, only 0 is returned if all arguments are found.
+# Use '--oneof' to return 0 if any one of the arguments are found.
+check_dep() {
+ [ $# -lt 1 ] && return 1
+ unset ONEOF
+ if [ "x$1" = "x--oneof" ]; then
+ local ONEOF="1"
+ shift
+ fi
+ while [ $# -gt 0 ]; do
+ if ! type -t "$1" >/dev/null 2>&1 ; then
+ writelog "Dependency check failed! Could not find '$1'."
+ isset ONEOF || return 1
+ else
+ isset ONEOF && return 0
+ fi
+ shift
+ done
+ isset ONEOF && return 1 || return 0
+}
+
+
+
+# TODO: This is only used once in the whole script:
+# to cleanup the os string stored in the xml
+# Since the rework of this script, the os strings come from
+# the satellite server which already gives us a sanitized string
+# thus this function might not be needed anymore, as calling it on
+# new gen os strings effectively does nothing.
+# Removes any non-alphanumerical and non-hyphen chars
+# from the given parameters.
+clean_string() {
+ if [ "$#" -ge 1 ]; then
+ echo "$@" | tr '[A-Z]' '[a-z]' | tr -d -c '[a-z0-9\-]'
+ else
+ tr '[A-Z]' '[a-z]' | tr -d -c '[a-z0-9\-]'
+ fi
+}