summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJonathan Bauer2021-05-04 13:38:35 +0200
committerJonathan Bauer2021-05-04 13:38:35 +0200
commit0bfcb437864bf0f43d88cf10013237dbf0525a0d (patch)
tree74004836ad12c9eecb7b0d0a00faf5243dbadf2e
parentMerge branch 'master' of git.openslx.org:openslx-ng/mltk (diff)
downloadmltk-0bfcb437864bf0f43d88cf10013237dbf0525a0d.tar.gz
mltk-0bfcb437864bf0f43d88cf10013237dbf0525a0d.tar.xz
mltk-0bfcb437864bf0f43d88cf10013237dbf0525a0d.zip
[run-virt-docker] initial run-virt support for docker
-rw-r--r--core/modules/run-virt-docker/data/etc/X11/Xreset.d/cleanup-container-session32
-rwxr-xr-xcore/modules/run-virt-docker/data/opt/openslx/pam/hooks/auth-final-exec.d/30-add-to-docker.sh23
-rwxr-xr-xcore/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/.bwlp-user-conf21
-rwxr-xr-xcore/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/docker-init74
-rwxr-xr-xcore/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/docker-init.desktop12
-rwxr-xr-xcore/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/includes/gio_allow_root_fix.inc12
-rwxr-xr-xcore/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/includes/gio_mount_netshare.inc173
-rwxr-xr-xcore/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/includes/init_bind_mount.inc57
-rw-r--r--core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/includes/init_user_context.inc92
-rwxr-xr-xcore/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/remount10
-rwxr-xr-xcore/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/run-virt.include59
-rw-r--r--core/modules/run-virt-docker/module.build13
-rw-r--r--core/modules/run-virt-docker/module.conf4
13 files changed, 582 insertions, 0 deletions
diff --git a/core/modules/run-virt-docker/data/etc/X11/Xreset.d/cleanup-container-session b/core/modules/run-virt-docker/data/etc/X11/Xreset.d/cleanup-container-session
new file mode 100644
index 00000000..07da7b37
--- /dev/null
+++ b/core/modules/run-virt-docker/data/etc/X11/Xreset.d/cleanup-container-session
@@ -0,0 +1,32 @@
+#!/bin/sh
+
+#exec &> /tmp/cleanup-container-session.log
+#set -x
+
+# remove scripts and autostart from $HOME
+USER_CONTAINER_CONTEXT="$HOME/.local/docker"
+USER_CONTAINER_AUTOSTART="$HOME/.config/autostart/docker-init.desktop"
+[ -f "$USER_CONTAINER_AUTOSTART" ] && rm -- "$USER_CONTAINER_AUTOSTART"
+[ -d "$USER_CONTAINER_CONTEXT" ] && rm -rf -- "$USER_CONTAINER_CONTEXT"
+
+# remove running containers
+[ -n "$(docker ps -aq)" ] && docker rm -f $(docker ps -aq) > /dev/null
+
+
+## CLEANUP GVFS RELATED STUFF
+#
+
+# TODO: i don't know how to properly unmount a users gvfs locations under GVFS_MOUNTDIR.
+# Either root can't do that for him nor root can't su into user and do it. (because of dbus thing)
+# Maybe one simple solution could be that root kills the gvfsd-smb process ?
+GVFS_MOUNTDIR="/run/user/$( id -u "$USER" )/gvfs"
+#for location in "$GVFS_MOUNTDIR"/*; do
+# [ -d "$location" ] && gio mount -u "$location"
+#done
+
+# Look for soft link in HOME and HOME/Desktop whith point into GVFS_MOUNTDIR and delete them
+FIND_OPT="-maxdepth 1 -type l"
+DEAD_LINKS=$(find $HOME $FIND_OPT && find ${HOME}/Desktop/ $FIND_OPT )
+for dead_link in $DEAD_LINKS; do
+ [ "$GVFS_MOUNTDIR" = "$(dirname $(readlink $dead_link))" ] && rm -f -- "$dead_link";
+done
diff --git a/core/modules/run-virt-docker/data/opt/openslx/pam/hooks/auth-final-exec.d/30-add-to-docker.sh b/core/modules/run-virt-docker/data/opt/openslx/pam/hooks/auth-final-exec.d/30-add-to-docker.sh
new file mode 100755
index 00000000..f5db36e4
--- /dev/null
+++ b/core/modules/run-virt-docker/data/opt/openslx/pam/hooks/auth-final-exec.d/30-add-to-docker.sh
@@ -0,0 +1,23 @@
+#!/bin/ash
+
+adduser "${PAM_USER}" "docker"
+
+# create a location for user bind mount
+# used in /opt/openslx/vmchooser/plugins/docker/includes/init-bind-mount.inc
+DOCKER_TMP="/tmp/docker"
+[ -e $DOCKER_TMP ] && rm -rf -- $DOCKER_TMP
+[ ! -e $DOCKER_TMP ] && mkdir -p $DOCKER_TMP && chmod 0777 $DOCKER_TMP
+
+# TODO Check if same user logs on to the system.
+# if prev_user != curr_user then delete existing /tmp/virt/docker/prev_user_uid:prev_user_gid/
+
+# This changes the subuid and subgid for the dockremap(user) to the current user and restards the docker daemon.
+# Because off this change in the docker daemon, for each userns will be a directory under /tmp/virt/docker/
+# so new users cannot uses previously downloade images by other user.
+# But it saves the next user from using images, created by the previous user.
+
+sed -i "s/dockremap:[0-9]\+.65536/dockremap:$(id -u ${PAM_USER}):65536/g" /etc/subuid
+sed -i "s/dockremap:[0-9]\+.65536/dockremap:$(id -g ${PAM_USER}):65536/g" /etc/subgid
+systemctl restart docker.service
+
+exit 0
diff --git a/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/.bwlp-user-conf b/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/.bwlp-user-conf
new file mode 100755
index 00000000..ae6cb288
--- /dev/null
+++ b/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/.bwlp-user-conf
@@ -0,0 +1,21 @@
+#!/bin/bash
+# this configfile holds env vars for user context
+
+# Functions (writelog(), cleanexit(), safesource())
+source /opt/openslx/vmchooser/run-virt-includes/vmchooser_runvirt_functions.inc
+
+# do not use writelog in this context
+function writelog () {
+ echo $1
+}
+
+export DOCKER_PLUGIN_DIR=""
+export DOCKER_INCLUDE_DIR=""
+export TMPDIR=""
+export RUNSCRIPT=""
+
+export VM_DISKFILE_RO=""
+
+export CONTAINER_BUILD_CONTEXT=""
+export CONTAINER_IMAGE_NAME=""
+export CONTAINER_RUN_OPTIONS=""
diff --git a/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/docker-init b/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/docker-init
new file mode 100755
index 00000000..5f52a16d
--- /dev/null
+++ b/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/docker-init
@@ -0,0 +1,74 @@
+#!/bin/bash
+
+USER_CONTAINER_CONFIG=""
+
+echo "+ source user_config $USER_CONTAINER_CONFIG"
+source $USER_CONTAINER_CONFIG
+
+load_image () {
+
+ IMAGE_SIZE=$(stat --printf="%s" $VM_DISKFILE_RO)
+ # check file size of VM_DISKFILE_RO is equals to 4096 = 4kB (because of padding)
+ if [[ $IMAGE_SIZE -eq 4096 ]]; then
+ echo "+ build container image with build_context"
+ echo "+ docker build --tag $CONTAINER_IMAGE_NAME $CONTAINER_BUILD_CONTEXT"
+ docker build --tag $CONTAINER_IMAGE_NAME $CONTAINER_BUILD_CONTEXT
+ else
+ # In this case a pre build container image (tar archive from "docker save ...")
+ # will be loaded into the local docker daemon.
+ echo "+ load container image"
+ # create TMP_FILE for image
+ local TMP_FILE=$(mktemp)
+ # write currently existing image ids into TMP_FILE
+ cp $VM_DISKFILE_RO $TMP_FILE
+ # recieve the RepoTag form the manifest.json inside the tar
+ local REPO_TAG=$(tar -axf $TMP_FILE manifest.json -O | jq -r '.[].RepoTags[0]')
+ # load image from tar file
+ docker load --input $TMP_FILE
+ # rename image
+ docker tag "$REPO_TAG" "$CONTAINER_IMAGE_NAME"
+ rm -f -- "$TMP_FILE"
+ fi
+ retval=$?
+ return $retval
+}
+
+main ()
+{
+ # TODO only check by image name could be bad, images whith a same name could exist
+
+ # check if the container_image_name already loaded in docker daemon
+ if [[ -z $(docker images $CONTAINER_IMAGE_NAME -q) ]]; then
+ echo "+ Image unknown by docker daemon ..."
+ load_image
+
+ if [[ "$retval" != "0" ]]; then
+ echo "...could not build/load container image!...giving up..."
+ return -1
+ fi
+ fi
+
+ if [[ -n "$(docker ps -aq)" ]]; then
+ echo "+ cleanup running container"
+ docker rm --force $(docker ps -aq) > /dev/null
+ fi
+
+ echo "+ start container..."
+ echo "+ docker run $CONTAINER_RUN_OPTIONS $CONTAINER_BIND_MOUNT_STRING $CONTAINER_IMAGE_NAME"
+ docker run $CONTAINER_RUN_OPTIONS $CONTAINER_BIND_MOUNT_STRING $CONTAINER_IMAGE_NAME
+
+ if [[ "$?" != "0" ]]; then
+ echo "...container start failed!...giving up..."
+ return -1
+ fi
+
+ if [[ -n $RUNSCRIPT ]]; then
+ echo "+ execute user runscript"
+ /bin/bash $RUNSCRIPT
+ fi
+}
+
+main
+
+# keeping terminal open
+bash
diff --git a/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/docker-init.desktop b/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/docker-init.desktop
new file mode 100755
index 00000000..87d418ea
--- /dev/null
+++ b/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/docker-init.desktop
@@ -0,0 +1,12 @@
+[Desktop Entry]
+Version=1.0
+Encoding=UTF-8
+Name=docker-init
+Type=Application
+Exec=
+Icon=
+Terminal=true
+StartupNotify=true
+Hidden=false
+GenericName=
+GenericName[en_US]= \ No newline at end of file
diff --git a/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/includes/gio_allow_root_fix.inc b/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/includes/gio_allow_root_fix.inc
new file mode 100755
index 00000000..9ef14d81
--- /dev/null
+++ b/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/includes/gio_allow_root_fix.inc
@@ -0,0 +1,12 @@
+#!/bin/bash
+writelog "+ apply 'allow_root' Option for gvfsd-fuse"
+
+# exec dummy call to start gvfsd and gvfsd-fuse
+gio mount
+
+# create gvfs user dir mybe it does not exist at this point
+mkdir -p "/run/user/$(id -u)/gvfs"
+
+fusermount -zu "/run/user/$(id -u)/gvfs"
+killall gvfsd-fuse
+/usr/lib/gvfs/gvfsd-fuse -o allow_root "/run/user/$(id -u)/gvfs"
diff --git a/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/includes/gio_mount_netshare.inc b/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/includes/gio_mount_netshare.inc
new file mode 100755
index 00000000..50e28fc0
--- /dev/null
+++ b/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/includes/gio_mount_netshare.inc
@@ -0,0 +1,173 @@
+#!/bin/bash
+
+# This script will be exectutet in docker lectures
+# and provide the functonallity to mount netshares in the bwlp maxilinux system for the logged in user.
+#
+
+# VARS
+#
+NETSHAREFILE="$CONFDIR/netshares"
+CONFIGFILE="$TMPDIR/configfile"
+
+MOUNTS=()
+DIRECTORY_LINKS=()
+
+GVFS_MOUNTDIR="/run/user/$( id -u "$USER" )/gvfs"
+
+declare -a ROHSHARES
+
+function cleanup_gio_mount()
+{
+ for i in "${MOUNTS[@]}"; do
+ gio mount -u "$i"
+ done
+
+ for i in "${DIRECTORY_LINKS[@]}"; do
+ unlink "$i"
+ done
+}
+
+function do_mount()
+{
+gio mount "$MOUNT_PREFIX$SHAREPATH" <<HEREDOC
+$MOUNT_USER
+
+$MOUNT_PASS
+HEREDOC
+ DO_MOUNT_RETVAL=$?
+}
+
+
+function provide_directory_links()
+{
+ # split sharepath into server address and share
+ # expected: //server.name.de/share
+ IFS='/' read -ra SHAREINFO <<< "$SHAREPATH" # str is read into an array as tokens separated by IFS
+
+ # index 0 and 1 are zero 2 is SHARESERVER 3 is SHARENAME
+ if [[ -z "${SHAREINFO[2]}" && -z "${SHAREINFO[3]}" ]]; then
+ writelog "+ shareinfo not as expected, can not create dir links"
+ return 1
+ fi
+
+ local SHARESERVER="${SHAREINFO[2]}"
+ local SHARE="${SHAREINFO[3]}"
+
+ local SHARE_MOUNT_POINT="$GVFS_MOUNTDIR/smb-share:server=${SHARESERVER},share=${SHARE}"
+
+ if [[ ! -e "$SHARE_MOUNT_POINT" ]]; then
+ writelog "+ mount directory for $SHAREPATH not found, can not create links!"
+ return 1
+ fi
+
+ NETSHARE_DIR["$SHARELETTER"]="$SHARE_MOUNT_POINT"
+
+ # create link do desktop and user home
+ ln -sf "${SHARE_MOUNT_POINT}" "${HOME}/${SHARENAME}"
+ mkdir -p "${HOME}/Desktop"
+ ln -sf "${SHARE_MOUNT_POINT}" "${HOME}/Desktop/${SHARENAME}"
+
+ # register cleanup function
+ DIRECTORY_LINKS+=("${HOME}/${SHARENAME}")
+ DIRECTORY_LINKS+=("${HOME}/Desktop/${SHARENAME}")
+}
+
+
+function mount_shares()
+{
+ for (( CONFIGROW = 1; CONFIGROW < ${#ROHSHARES[@]}; CONFIGROW++ )); do
+ SHAREPATH=$(echo "${ROHSHARES[CONFIGROW]}" | cut -f 1 -d$'\t' | \
+ sed 's:\\:/:g')
+ SHARELETTER=$(echo "${ROHSHARES[CONFIGROW]}" | cut -f 2 -d$'\t' | \
+ sed 's/://g') # Laufwerksbuchstabe ohne :
+ SHARENAME=$(echo "${ROHSHARES[CONFIGROW]}" | cut -f 3 -d$'\t' | sed 's/ /_/g') # Leerzeichen raus.
+ SHAREUSER=$(echo "${ROHSHARES[CONFIGROW]}" | cut -f 4 -d$'\t') # Username, bei Userhome nicht vorhanden
+ SHAREPASS=$(echo "${ROHSHARES[CONFIGROW]}" | cut -f 5 -d$'\t') # User-PW, bei Userhome nicht vorhanden
+
+
+ MOUNT_PREFIX="smb:"
+
+ if [[ -z "$SHAREUSER" || -z "$SHAREPASS" ]]; then
+ MOUNT_USER="$USER"
+ MOUNT_PASS="$PW"
+ else
+ MOUNT_USER="$SHAREUSER"
+ MOUNT_PASS="$SHAREPASS"
+ fi
+
+ writelog "+ mount netshare $MOUNT_PREFIX$SHAREPATH"
+ do_mount > /dev/null
+
+ if [[ "$DO_MOUNT_RETVAL" -eq 0 ]]; then
+ writelog "+ ... mount was successfull"
+ sleep 1
+ provide_directory_links
+ MOUNTS+=("$MOUNT_PREFIX$SHAREPATH")
+ else
+ writelog "+ ... mount faild"
+ fi
+ done
+
+ unset MOUNT_USER MOUNT_PASS
+}
+
+
+function gio_mount()
+{
+ # CLEANUP
+ rm -f -- "$CONFIGFILE"
+ touch "$CONFIGFILE"
+ # TODO existing gio mounts shouldn´t exist at this points
+ # remove them anyway
+ for location in "$GVFS_MOUNTDIR"/*; do
+ [ -d "$location" ] && gio mount -u "$location"
+ done
+ sleep 1
+
+ # Fill CONFIGFILE with pwdaemon info, how it is done in /opt/openslx/vmchooser/run-virt.d/setup_virtual_floppy.inc
+ # TODO some checks if everthing run fine.
+ pwdaemon --query "$HOME/.pwsocket" > "$CONFIGFILE"
+ sed -i 's/^/192.168.101.1\t/' "$CONFIGFILE"
+
+ # Attach netshares to CONFIGFILE
+ cat "$NETSHAREFILE" >> "$CONFIGFILE"
+
+ # With this preparetion of CONFIGFILE functions from /opt/openslx/vmchooser/data/linux/includes/
+ # can be uesed. NATADDR, PORT, KEYTEMP, RAWKEYTEMP and BYTES required in get_creds
+ NATADDR=$( head -n 1 "$CONFIGFILE" | cut -f 1 -d$'\t' )
+ PORT=$( head -n 1 "$CONFIGFILE" | cut -f 2 -d$'\t' )
+ KEYTEMP="$( mktemp -t XXXXXXXXXX.dat )"
+ RAWKEYTEMP="$( mktemp -t XXXXXXXXXX.dat )"
+ BYTES=256
+
+ source /opt/openslx/vmchooser/data/linux/includes/10_functions.inc
+ source /opt/openslx/vmchooser/data/linux/includes/20_get_creds.inc
+ source /opt/openslx/vmchooser/data/linux/includes/30_get_shares.inc
+
+ # getting user credentials
+ get_creds
+
+ # load shares from CONFIGFILE (../metadata/netshares) into ROHSHARES variable
+ get_shares
+
+ # check if required VARS for mounting are non zero
+ if [[ -n "$ROHSHARES" && -n "$PW" && -n "$USER" ]]; then
+ # mount each mountpoint
+ writelog "+ initialize complete ... mount shares"
+ mount_shares
+ else
+ writelog "+ initialize failed"
+ fi
+}
+
+# check if size of NETSHAREFILE > 0
+if [[ -s "$NETSHAREFILE" ]]; then
+ writelog "+ NETSHAREFILE: ${NETSHAREFILE} contains informations for network drives... initialize gio mount"
+ gio_mount
+ add_cleanup cleanup_gio_mount
+else
+ writelog "+ NETSHAREFILE: ${NETSHAREFILE} empty ... nothing to mount"
+fi
+
+unset PW
+rm -f -- "$KEYTEMP" "$RAWKEYTEMP" "$CONFIGFILE"
diff --git a/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/includes/init_bind_mount.inc b/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/includes/init_bind_mount.inc
new file mode 100755
index 00000000..ad82ef51
--- /dev/null
+++ b/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/includes/init_bind_mount.inc
@@ -0,0 +1,57 @@
+#!/bin/bash
+
+## required vars
+# TMPDIR=/tmp/virt/<CURRENT_USER>/<PID>/
+# USER_CONTAINER_CONFIG
+# NETSHARE_DIR
+
+# vars
+BIND_MOUNT_FILE="$CONFDIR/container_meta.json"
+# TODO: Maybe make this an array to support spaces
+BIND_MOUNT_STRING=""
+
+
+BIND_MOUNT_COUNT="$( cat "$BIND_MOUNT_FILE" | jq '.bind_mount_config | length' )"
+
+for (( index=0; index < "$BIND_MOUNT_COUNT"; index++ )); do
+
+ BIND_MOUNT_INFO="$( jq .bind_mount_config["$index"] "$BIND_MOUNT_FILE" )"
+
+ # expecting source to be a MOUNT_LETTER, wich must replaced with the directory
+ BIND_MOUNT_SOURCE="$( jq -r .source <<< "$BIND_MOUNT_INFO" )"
+ BIND_MOUNT_TARGET="$( jq -r .target <<< "$BIND_MOUNT_INFO" )"
+ BIND_MOUNT_OPTION="$( jq -r .option <<< "$BIND_MOUNT_INFO" )"
+
+ if [[ -z "$BIND_MOUNT_SOURCE" || -z "$BIND_MOUNT_TARGET" ]]; then
+ writelog "+ no proper bind mount option provided!"
+ continue
+ fi
+
+ # USER_HOME is selected
+ if [[ "$BIND_MOUNT_SOURCE" == "USER_HOME" ]]; then
+ if [[ -d "$HOME/PERSISTENT" ]]; then
+ BIND_MOUNT_STRING+=" --mount type=bind,source=$HOME/PERSISTENT,target=$BIND_MOUNT_TARGET"
+ else
+ # user has no PERSISTENT, maybe this is a demo user just mount $HOME
+ BIND_MOUNT_STRING+=" --mount type=bind,source=$HOME,target=$BIND_MOUNT_TARGET"
+ fi
+
+ # If USER_TMP is used, create a locaten for client user and bind mount into container
+ elif [[ "$BIND_MOUNT_SOURCE" == "USER_TMP" ]]; then
+ # DOCKER_TMP created and cleand in opt/openslx/pam/hooks/auth-final-exec.d/30-add-to-docker.sh
+ DOCKER_TMP="/tmp/docker"
+ DOCKER_USER_TMP="$DOCKER_TMP/$(id -u)"
+ [ ! -e $DOCKER_USER_TMP ] && mkdir -p $DOCKER_USER_TMP && chmod 0700 $DOCKER_USER_TMP
+ BIND_MOUNT_STRING+=" --mount type=bind,source=$DOCKER_USER_TMP,target=$BIND_MOUNT_TARGET"
+
+ elif [[ -z "${NETSHARE_DIR[$BIND_MOUNT_SOURCE]}" ]]; then
+ writelog "+ no bind mount mapping for letter $BIND_MOUNT_SOURCE found!"
+ continue
+ else
+ BIND_MOUNT_STRING+=" --mount type=bind,\\\"source=${NETSHARE_DIR[$BIND_MOUNT_SOURCE]}\\\",target=$BIND_MOUNT_TARGET"
+ fi
+
+done
+
+writelog "+ write final CONTAINER_BIND_MOUNT_STRING $BIND_MOUNT_STRING in config $USER_CONTAINER_CONFIG"
+echo "CONTAINER_BIND_MOUNT_STRING=\"${BIND_MOUNT_STRING}\"" >> ${USER_CONTAINER_CONFIG}
diff --git a/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/includes/init_user_context.inc b/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/includes/init_user_context.inc
new file mode 100644
index 00000000..99ba4580
--- /dev/null
+++ b/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/includes/init_user_context.inc
@@ -0,0 +1,92 @@
+#!/bin/bash
+
+
+function process_container_meta()
+{
+ writelog "+ process container_meta.json"
+ # Try to make a valid CONTAINER_IMAGE_NAME
+ export CONTAINER_IMAGE_NAME=$( jq -r '.image_name' "$CONFDIR/container_meta.json" | \
+ tr '[:upper:]' '[:lower:]' | sed -e 's/^[[:space:]]*//g' -e 's/[[:space:]]*$//g' | sed -e 's/[[:space:]]/_/g')
+ export CONTAINER_RUN_OPTIONS=$( jq -r '.run_options' "$CONFDIR/container_meta.json" )
+
+
+ # set build context
+ build_context_method=$( jq -r '.build_context_method' "$CONFDIR/container_meta.json" )
+ if [[ "$build_context_method" == "0" ]]; then
+ writelog "+ container_build_context: dockerfile"
+ export CONTAINER_BUILD_CONTEXT="$CONFDIR/"
+ elif [[ "$build_context_method" == "1" ]]; then
+ writelog "+ container_build_context: git url"
+ export CONTAINER_BUILD_CONTEXT=$( jq -r '.build_context_url' "$CONFDIR/container_meta.json" )
+ else
+ writelog "+ no proper build_context_method!"
+ cleanexit 1
+ fi
+}
+
+
+function setup_user_container_context()
+{
+ mkdir -p "$USER_CONTAINER_CONTEXT"
+ # init user directory with scripts
+ cp "$DOCKER_PLUGIN_DIR/docker-init" "$USER_CONTAINER_CONTEXT/"
+ cp "$DOCKER_PLUGIN_DIR/remount" "$USER_CONTAINER_CONTEXT/"
+ cp "$DOCKER_PLUGIN_DIR/.bwlp-user-conf" "$USER_CONTAINER_CONFIG"
+ chmod u+x "$USER_CONTAINER_CONTEXT/docker-init"
+ chmod u+x "$USER_CONTAINER_CONTEXT/remount"
+}
+
+
+function setup_user_container_autostart()
+{
+ # TODO: maybe there is a better way to load and start the container which is used in the current lecture
+ mkdir -p "$HOME/.config/autostart/"
+ cp -f "$DOCKER_PLUGIN_DIR/docker-init.desktop" "$HOME/.config/autostart/"
+ sed -i "s:Exec=:Exec=$USER_CONTAINER_CONTEXT/docker-init:" "$HOME/.config/autostart/docker-init.desktop"
+}
+
+
+function init_user_container_config()
+{
+ if [[ ! -f "$USER_CONTAINER_CONFIG" ]]; then
+ writelog "+ USER_CONTAINER_CONFIG: $USER_CONTAINER_CONFIG does not exist!"
+ cleanexit 1
+ fi
+
+ process_container_meta
+
+ writelog "+ init USER_CONTAINER_CONFIG: $USER_CONTAINER_CONFIG"
+ sed -i "s#export DOCKER_PLUGIN_DIR=".*"#export DOCKER_PLUGIN_DIR=\"$DOCKER_PLUGIN_DIR\"#" "$USER_CONTAINER_CONFIG"
+ sed -i "s#export DOCKER_INCLUDE_DIR=".*"#export DOCKER_INCLUDE_DIR=\"$DOCKER_INCLUDE_DIR\"#" "$USER_CONTAINER_CONFIG"
+ sed -i "s#export TMPDIR=".*"#export TMPDIR=\"$TMPDIR\"#" "$USER_CONTAINER_CONFIG"
+
+ sed -i "s#export VM_DISKFILE_RO=".*"#export VM_DISKFILE_RO=\"$VM_DISKFILE_RO\"#" "$USER_CONTAINER_CONFIG"
+
+ sed -i "s#export CONTAINER_BUILD_CONTEXT=".*"#export CONTAINER_BUILD_CONTEXT=\"$CONTAINER_BUILD_CONTEXT\"#" "$USER_CONTAINER_CONFIG"
+ sed -i "s#export CONTAINER_IMAGE_NAME=".*"#export CONTAINER_IMAGE_NAME=\"$CONTAINER_IMAGE_NAME\"#" "$USER_CONTAINER_CONFIG"
+ sed -i "s#export CONTAINER_RUN_OPTIONS=".*"#export CONTAINER_RUN_OPTIONS=\"$CONTAINER_RUN_OPTIONS\"#" "$USER_CONTAINER_CONFIG"
+
+ local RUNSCRIPT="$CONFDIR/runscript"
+ # check if runscript file contains more than default line "ext=;visibility=1;soundMuted=-1"
+ if [[ "$( < "$RUNSCRIPT" wc -l )" -gt "1" ]]; then
+ sed -i "s#export RUNSCRIPT=".*"#export RUNSCRIPT=\"$RUNSCRIPT\"#" "$USER_CONTAINER_CONFIG"
+ fi
+
+ sed -i "s#USER_CONTAINER_CONFIG=".*"#USER_CONTAINER_CONFIG=\"$USER_CONTAINER_CONFIG\"#" "$USER_CONTAINER_CONTEXT/docker-init"
+}
+
+
+function cleanup_user_container_context()
+{
+ [ -d "$USER_CONTAINER_CONTEXT" ] && rm -rf -- "$USER_CONTAINER_CONTEXT"
+ [ -f "$HOME/.config/autostart/docker-init.desktop" ] && rm "$HOME/.config/autostart/docker-init.desktop"
+
+ # force remove all containers
+ [ -n "$(docker ps -aq)" ] && docker rm -f $(docker ps -aq) > /dev/null
+}
+
+
+setup_user_container_context
+setup_user_container_autostart
+init_user_container_config
+add_cleanup cleanup_user_container_context
diff --git a/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/remount b/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/remount
new file mode 100755
index 00000000..d4a4f5de
--- /dev/null
+++ b/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/remount
@@ -0,0 +1,10 @@
+#!/bin/bash
+#
+
+source "$HOME/.bwlp-user-conf"
+
+writelog "+ start mounting"
+$(safesource "${DOCKER_INCLUDE_DIR}/gio_mount_netshare.inc")
+
+writelog "+ create bind mount string"
+$(safesource "${DOCKER_INCLUDE_DIR}/init_bind_mount.inc")
diff --git a/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/run-virt.include b/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/run-virt.include
new file mode 100755
index 00000000..55f89e01
--- /dev/null
+++ b/core/modules/run-virt-docker/data/opt/openslx/vmchooser/plugins/docker/run-virt.include
@@ -0,0 +1,59 @@
+#!/bin/bash
+###############################################################################
+# -----------------------------------------------------------------------------
+#
+# Copyright (c) 2009..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 bwlehrpool@hs-offenburg.de.
+#
+# General information about bwLehrpool can be found at https://bwlehrpool.de
+#
+# -----------------------------------------------------------------------------
+# run-virt.include
+# - qemu/kvm plugin for vmchooser run-virt
+################################################################################
+
+# BASH_SOURCE[0] contains the file being sourced, namely this one
+declare -rg DOCKER_PLUGIN_DIR="$(dirname "${BASH_SOURCE[0]}")"
+declare -rg DOCKER_INCLUDE_DIR="${DOCKER_PLUGIN_DIR}/includes"
+
+# TODO make this part of the metadata coming from the server
+# TBD: "firewall printer usb slxfloppy sound netshares"
+declare -rg PLUGIN_FEATURES=""
+
+run_plugin() {
+
+ # VMX == bwlp-container-info.tar.gz
+ writelog "+ unpacking container ressources"
+ tar -xzvf "$TMPCONFIG" --directory "$CONFDIR"
+
+ # VARS
+ # location of scripts and config files which will be used in desktop
+ export USER_CONTAINER_CONTEXT="$HOME/.local/docker"
+ # config file which will be filed with vars in the follwing process
+ export USER_CONTAINER_CONFIG="$USER_CONTAINER_CONTEXT/.bwlp-user-conf"
+ # dictonary which maps a drive letter to a directory
+ declare -Ag NETSHARE_DIR
+
+ # apply "allow_root" option to gvfsd-fuse, so docker can bind mount gvfs network shares
+ writelog "+ gio_allow_root_fix.inc"
+ $( safesource "${DOCKER_INCLUDE_DIR}/gio_allow_root_fix.inc" )
+
+ # mount netshares from CONFDIR/netshares
+ writelog "+ gio_mount_netshare.inc"
+ $( safesource "${DOCKER_INCLUDE_DIR}/gio_mount_netshare.inc" )
+
+ writelog "+ init user container context"
+ $( safesource "${DOCKER_INCLUDE_DIR}/init_user_context.inc" )
+
+ # init bind mount option for container
+ writelog "+ init_bind_mount.inc"
+ $( safesource "${DOCKER_INCLUDE_DIR}/init_bind_mount.inc" )
+
+ # HACK: using the modified version of the wrapper script
+ declare -rg VIRTCMD="startxfce4"
+}
diff --git a/core/modules/run-virt-docker/module.build b/core/modules/run-virt-docker/module.build
new file mode 100644
index 00000000..5086d1bc
--- /dev/null
+++ b/core/modules/run-virt-docker/module.build
@@ -0,0 +1,13 @@
+#!/bin/bash
+# fake module simply copying its data/ files
+fetch_source() {
+ :
+}
+
+build() {
+ :
+}
+
+post_copy() {
+ :
+}
diff --git a/core/modules/run-virt-docker/module.conf b/core/modules/run-virt-docker/module.conf
new file mode 100644
index 00000000..8811668a
--- /dev/null
+++ b/core/modules/run-virt-docker/module.conf
@@ -0,0 +1,4 @@
+#!/bin/bash
+REQUIRED_BINARIES=""
+REQUIRED_LIBRARIES=""
+REQUIRED_DIRECTORIES=""