diff --git a/src/common/scripts/kasm_hook_scripts/kasm_pre_shutdown_user.sh b/src/common/scripts/kasm_hook_scripts/kasm_pre_shutdown_user.sh index 1fa44f0..b905461 100644 --- a/src/common/scripts/kasm_hook_scripts/kasm_pre_shutdown_user.sh +++ b/src/common/scripts/kasm_hook_scripts/kasm_pre_shutdown_user.sh @@ -1,6 +1,25 @@ #!/usr/bin/env bash -set -e -echo "Executing kasm_pre_shutdown_user.sh" + +APP_NAME=$(basename "$0") + +log () { + if [ ! -z "${1}" ]; then + LOG_LEVEL="${2:-DEBUG}" + INGEST_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ") + echo "${INGEST_DATE} ${LOG_LEVEL} (${APP_NAME}): $1" + if [ ! -z "${KASM_API_JWT}" ] && [ ! -z "${KASM_API_HOST}" ] && [ ! -z "${KASM_API_PORT}" ]; then + http_proxy="" https_proxy="" curl https://${KASM_API_HOST}:${KASM_API_PORT}/api/kasm_session_log?token=${KASM_API_JWT} --max-time 1 -X POST -H 'Content-Type: application/json' -d '[{ "host": "'"${KASM_ID}"'", "application": "Session", "ingest_date": "'"${INGEST_DATE}"'", "message": "'"$1"'", "levelname": "'"${LOG_LEVEL}"'", "process": "'"${APP_NAME}"'", "kasm_user_name": "'"${KASM_USER_NAME}"'", "kasm_id": "'"${KASM_ID}"'" }]' -k + fi + fi +} + +cleanup() { + log "The kasm_pre_shutdown_user script was interrupted." "ERROR" +} + +trap cleanup 2 6 9 15 + +log "Executing kasm_pre_shutdown_user.sh" "INFO" PAUSE_ON_EXIT="false" if [ -z ${KASM_PROFILE_CHUNK_SIZE} ]; then @@ -53,22 +72,34 @@ if [ ! -z "$KASM_PROFILE_LDR" ]; then SIZE_LIMIT_MB=$(echo "$KASM_PROFILE_SIZE_LIMIT / 1000" | bc) if [[ $CURRENT_SIZE -gt KASM_PROFILE_SIZE_LIMIT ]]; then http_proxy="" https_proxy="" curl -k "https://${KASM_API_HOST}:${KASM_API_PORT}/api/set_kasm_session_status?token=${KASM_API_JWT}" -H 'Content-Type: application/json' -d '{"destroyed": true}' - echo 'Profile size limit exceeded.' + log 'Profile size limit exceeded.' 'WARNING' exit 0 fi fi if [ -z "$kasm_profile_sync_found" ]; then - echo >&2 "Profile sync not available" + log "Profile sync not available" else - echo "Packing and uploading user profile to object storage." + log "Packing and uploading user profile to object storage." + PROFILE_SYNC_STATUS=1 if [[ $DEBUG == true ]]; then - http_proxy="" https_proxy="" /usr/bin/kasm-profile-sync --upload /home/kasm-user --insecure --filter "${KASM_PROFILE_FILTER}" --remote ${KASM_API_HOST} --port ${KASM_API_PORT} -c ${KASM_PROFILE_CHUNK_SIZE} --token ${KASM_API_JWT} --verbose + OUTPUT=$(http_proxy="" https_proxy="" /usr/bin/kasm-profile-sync --upload /home/kasm-user --insecure --filter "${KASM_PROFILE_FILTER}" --remote ${KASM_API_HOST} --port ${KASM_API_PORT} -c ${KASM_PROFILE_CHUNK_SIZE} --token ${KASM_API_JWT} --verbose 2>&1 ) + PROFILE_SYNC_STATUS=$? else - http_proxy="" https_proxy="" /usr/bin/kasm-profile-sync --upload /home/kasm-user --insecure --filter "${KASM_PROFILE_FILTER}" --remote ${KASM_API_HOST} --port ${KASM_API_PORT} -c ${KASM_PROFILE_CHUNK_SIZE} --token ${KASM_API_JWT} + OUTPUT=$(http_proxy="" https_proxy="" /usr/bin/kasm-profile-sync --upload /home/kasm-user --insecure --filter "${KASM_PROFILE_FILTER}" --remote ${KASM_API_HOST} --port ${KASM_API_PORT} -c ${KASM_PROFILE_CHUNK_SIZE} --token ${KASM_API_JWT} 2>&1 ) + PROFILE_SYNC_STATUS=$? fi - echo "Profile upload complete." + + while IFS= read -r line; do + log "$line" + done <<< "$OUTPUT" + + if [ $PROFILE_SYNC_STATUS -ne 0 ]; then + log "Failed to syncronize user profile, see debug logs." "ERROR" + else + log "Profile upload complete." + fi fi fi -echo "Done" +echo "Done" \ No newline at end of file diff --git a/src/common/startup_scripts/vnc_startup.sh b/src/common/startup_scripts/vnc_startup.sh index de20ab7..3265a14 100755 --- a/src/common/startup_scripts/vnc_startup.sh +++ b/src/common/startup_scripts/vnc_startup.sh @@ -2,6 +2,19 @@ ### every exit != 0 fails the script set -e +APP_NAME=$(basename "$0") + +log () { + if [ ! -z "${1}" ]; then + LOG_LEVEL="${2:-DEBUG}" + INGEST_DATE=$(date -u +"%Y-%m-%dT%H:%M:%SZ") + echo "${INGEST_DATE} ${LOG_LEVEL} (${APP_NAME}): $1" + if [ ! -z "${KASM_API_JWT}" ] && [ ! -z "${KASM_API_HOST}" ] && [ ! -z "${KASM_API_PORT}" ]; then + http_proxy="" https_proxy="" curl https://${KASM_API_HOST}:${KASM_API_PORT}/api/kasm_session_log?token=${KASM_API_JWT} --max-time 1 -X POST -H 'Content-Type: application/json' -d '[{ "host": "'"${KASM_ID}"'", "application": "Session", "ingest_date": "'"${INGEST_DATE}"'", "message": "'"$1"'", "levelname": "'"${LOG_LEVEL}"'", "process": "'"${APP_NAME}"'", "kasm_user_name": "'"${KASM_USER_NAME}"'", "kasm_id": "'"${KASM_ID}"'" }]' -k + fi + fi +} + no_proxy="localhost,127.0.0.1" if [ -f /usr/bin/kasm-profile-sync ]; then @@ -66,20 +79,27 @@ function pull_profile (){ return fi - echo "Downloading and unpacking user profile from object storage." + log "Downloading and unpacking user profile from object storage." set +e if [[ $DEBUG == true ]]; then - http_proxy="" https_proxy="" /usr/bin/kasm-profile-sync --download /home/kasm-user --insecure --remote ${KASM_API_HOST} --port ${KASM_API_PORT} -c ${KASM_PROFILE_CHUNK_SIZE} --token ${KASM_API_JWT} --verbose + OUTPUT=$(http_proxy="" https_proxy="" /usr/bin/kasm-profile-sync --download /home/kasm-user --insecure --remote ${KASM_API_HOST} --port ${KASM_API_PORT} -c ${KASM_PROFILE_CHUNK_SIZE} --token ${KASM_API_JWT} --verbose 2>&1 ) else - http_proxy="" https_proxy="" /usr/bin/kasm-profile-sync --download /home/kasm-user --insecure --remote ${KASM_API_HOST} --port ${KASM_API_PORT} -c ${KASM_PROFILE_CHUNK_SIZE} --token ${KASM_API_JWT} + OUTPUT=$(http_proxy="" https_proxy="" /usr/bin/kasm-profile-sync --download /home/kasm-user --insecure --remote ${KASM_API_HOST} --port ${KASM_API_PORT} -c ${KASM_PROFILE_CHUNK_SIZE} --token ${KASM_API_JWT} 2>&1 ) fi + + # log output of profile sync + while IFS= read -r line; do + log "$line" + done <<< "$OUTPUT" + + # exit and log a non-zero exit code PROCESS_SYNC_EXIT_CODE=$? set -e if (( PROCESS_SYNC_EXIT_CODE > 1 )); then - echo "Profile-sync failed with a non-recoverable error. See server side logs for more details." + log "Profile-sync failed with a non-recoverable error. See server side logs for more details." "ERROR" exit 1 fi - echo "Profile load complete." + log "Profile load complete." # Update the status of the container to running sleep 3 http_proxy="" https_proxy="" curl -k "https://${KASM_API_HOST}:${KASM_API_PORT}/api/set_kasm_session_status?token=${KASM_API_JWT}" -H 'Content-Type: application/json' -d '{"status": "running"}' @@ -108,6 +128,10 @@ function profile_size_check(){ notify-send "Profile Size" "Your home profile size is now under the limit and will be saved when your session is terminated." -i /usr/share/icons/ubuntu-mono-dark/apps/22/dropboxstatus-logo.svg -t 57000 fi fi + + if [ -f /tmp/.kasm_container_shutdown_failure ]; then + notify-send "Profile Size" "Your profile failed to save. Contact your administrator for assistance." -i /usr/share/icons/ubuntu-mono-dark/apps/22/dropboxstatus-logo.svg -t 57000 + fi done fi } @@ -119,9 +143,7 @@ function cleanup () { } function start_kasmvnc (){ - if [[ $DEBUG == true ]]; then - echo -e "\n------------------ Start KasmVNC Server ------------------------" - fi + log "Starting KasmVNC" DISPLAY_NUM=$(echo $DISPLAY | grep -Po ':\d+') @@ -166,7 +188,7 @@ function start_kasmvnc (){ } function start_window_manager (){ - echo -e "\n------------------ Xfce4 window manager startup------------------" + log "Starting Window Manager" if [ "${START_XFCE4}" == "1" ] ; then if [ -f /opt/VirtualGL/bin/vglrun ] && [ ! -z "${KASM_EGL_CARD}" ] && [ ! -z "${KASM_RENDERD}" ] && [ -O "${KASM_RENDERD}" ] && [ -O "${KASM_EGL_CARD}" ] ; then @@ -188,7 +210,7 @@ function start_window_manager (){ function start_audio_out_websocket (){ if [[ ${KASM_SVC_AUDIO:-1} == 1 ]]; then - echo 'Starting audio websocket server' + log 'Starting audio websocket server' $STARTUPDIR/jsmpeg/kasm_audio_out-linux kasmaudio 8081 4901 ${HOME}/.vnc/self.pem ${HOME}/.vnc/self.pem "kasm_user:$VNC_PW" & KASM_PROCS['kasm_audio_out_websocket']=$! @@ -202,7 +224,7 @@ function start_audio_out_websocket (){ function start_audio_out (){ if [[ ${KASM_SVC_AUDIO:-1} == 1 ]]; then - echo 'Starting audio server' + log 'Starting audio server' if [ "${START_PULSEAUDIO:-0}" == "1" ] ; then @@ -226,7 +248,7 @@ function start_audio_out (){ function start_audio_in (){ if [[ ${KASM_SVC_AUDIO_INPUT:-1} == 1 ]]; then - echo 'Starting audio input server' + log 'Starting audio input server' $STARTUPDIR/audio_input/kasm_audio_input_server --ssl --auth-token "kasm_user:$VNC_PW" --cert ${HOME}/.vnc/self.pem --certkey ${HOME}/.vnc/self.pem & KASM_PROCS['kasm_audio_in']=$! @@ -240,7 +262,7 @@ function start_audio_in (){ function start_upload (){ if [[ ${KASM_SVC_UPLOADS:-1} == 1 ]]; then - echo 'Starting upload server' + log 'Starting upload server' $STARTUPDIR/upload_server/kasm_upload_server --ssl --auth-token "kasm_user:$VNC_PW" --port 4902 --upload_dir ${HOME}/Uploads & KASM_PROCS['upload_server']=$! @@ -254,7 +276,7 @@ function start_upload (){ function start_gamepad (){ if [[ ${KASM_SVC_GAMEPAD:-1} == 1 ]]; then - echo 'Starting gamepad server' + log 'Starting gamepad server' $STARTUPDIR/gamepad/kasm_gamepad_server --ssl --auth-token "kasm_user:$VNC_PW" --cert ${HOME}/.vnc/self.pem --certkey ${HOME}/.vnc/self.pem & KASM_PROCS['kasm_gamepad']=$! @@ -268,7 +290,7 @@ function start_gamepad (){ function start_webcam (){ if [[ ${KASM_SVC_WEBCAM:-1} == 1 ]] && [[ -e /dev/video0 ]]; then - echo 'Starting webcam server' + log 'Starting webcam server' if [[ $DEBUG == true ]]; then $STARTUPDIR/webcam/kasm_webcam_server --debug --port 4905 --ssl --cert ${HOME}/.vnc/self.pem --certkey ${HOME}/.vnc/self.pem & else @@ -286,7 +308,7 @@ function start_webcam (){ function start_printer (){ if [[ ${KASM_SVC_PRINTER:-1} == 1 ]]; then - echo 'Starting printer service' + log 'Starting printer service' if [[ $DEBUG == true ]]; then $STARTUPDIR/printer/kasm_printer_service --debug --directory $HOME/PDF --relay /tmp/printer & else @@ -312,6 +334,7 @@ function custom_startup (){ "$custom_startup_script" & KASM_PROCS['custom_startup']=$! + log "Executed custom startup script." fi } @@ -323,7 +346,7 @@ function ensure_recorder_running () { local kasm_recorder_process="/dockerstartup/recorder/kasm_recorder_service" local kasm_recorder_ack="/tmp/kasm_recorder.ack" - if [[ -f "$kasm_recorder_ack" ]]; then + if [[ -f "$kasm_recorder_ack" ]]; then local ack_user=$(stat -c '%U' $kasm_recorder_ack) if [[ "$ack_user" == "kasm-recorder" ]]; then SECONDS=0 #SECONDS is a built in bash variable that is incremented approximately every second @@ -336,20 +359,20 @@ function ensure_recorder_running () { if [[ -z $kasm_recorder_pid ]]; then # This leverages the outside while loop that calls this function to provider checking ever x seconds. if [[ -z $recorder_pid ]] && (( $SECONDS > 15 )); then - echo "$kasm_recorder_process: not started, exiting" + log "$kasm_recorder_process: not started, exiting" "ERROR" exit 0 fi kasm_recorder_pid=$recorder_pid else if [[ -z $recorder_pid ]]; then - echo "$kasm_recorder_process: not running, exiting" + log "$kasm_recorder_process: not running, exiting" "ERROR" exit 0 fi recorder_user=$(ps -p $recorder_pid -o user=) if [[ $recorder_user != "kasm-recorder" ]]; then - echo "$kasm_recorder_process: not running as kasm-recorder, exiting" + log "$kasm_recorder_process: not running as kasm-recorder, exiting" "ERROR" exit 0 fi fi @@ -407,10 +430,7 @@ if [[ -f $PASSWD_PATH ]]; then echo -e "\n--------- purging existing VNC password settings ---------" rm -f $PASSWD_PATH fi -#VNC_PW_HASH=$(python3 -c "import crypt; print(crypt.crypt('${VNC_PW}', '\$5\$kasm\$'));") -#VNC_VIEW_PW_HASH=$(python3 -c "import crypt; print(crypt.crypt('${VNC_VIEW_ONLY_PW}', '\$5\$kasm\$'));") -#echo "kasm_user:${VNC_PW_HASH}:ow" > $PASSWD_PATH -#echo "kasm_viewer:${VNC_VIEW_PW_HASH}:" >> $PASSWD_PATH + echo -e "${VNC_PW}\n${VNC_PW}\n" | kasmvncpasswd -u kasm_user -wo echo -e "${VNC_PW}\n${VNC_PW}\n" | kasmvncpasswd -u kasm_viewer -r chmod 600 $PASSWD_PATH @@ -438,7 +458,7 @@ echo -e "\n\n------------------ KasmVNC environment started ------------------" tail -f $HOME/.vnc/*$DISPLAY.log & KASMIP=$(hostname -i) -echo "Kasm User ${KASM_USER}(${KASM_USER_ID}) started container id ${HOSTNAME} with local IP address ${KASMIP}" +log "Kasm User ${KASM_USER}(${KASM_USER_ID}) started container id ${HOSTNAME} with local IP address ${KASMIP}" "INFO" # start custom startup script custom_startup @@ -458,20 +478,20 @@ do case $process in kasmvnc) if [ "$KASMVNC_AUTO_RECOVER" = true ] ; then - echo "KasmVNC crashed, restarting" + log "KasmVNC crashed, restarting" "WARNING" start_kasmvnc else - echo "KasmVNC crashed, exiting container" + log "KasmVNC crashed, exiting container" "ERROR" exit 1 fi ;; window_manager) - echo "Window manager crashed, restarting" + log "Window manager crashed, restarting" "WARNING" if [[ ${KASM_SVC_RECORDER:-0} == 1 ]]; then - echo "Waiting for recorder service to upload all pending recordings" + log "Waiting for recorder service to upload all pending recordings" ensure_recorder_terminates_gracefully - echo "Recorder service has terminated, exiting container" + log "Recorder service has terminated, exiting container" "ERROR" exit 1 fi @@ -528,4 +548,4 @@ do done -echo "Exiting Kasm container" +log "Exiting Kasm container"