#!/usr/bin/env -S bash API_BASE_URL=https://labmanager-api.edu-al.unipmn.it/api/1.0 MAX_RETRY=5 RETRY_DELAY=5 NORMAL_CONFIG_NAME=normale DEBUG=0 # Sysadmin can override local vars here: CONFFILE=/etc/default/labmanager # Load configuration override if present: if [ -e ${CONFFILE} ]; then . ${CONFFILE} fi if [[ "-d" == "$2" ]]; then DEBUG=1 fi # execute a task and on fail execute it again MAX_RETRY times every RETRY_DELAY seconds retry() { local n=1 local max=$MAX_RETRY local delay=$RETRY_DELAY while true; do "$@" ret=$? if [[ $ret == 0 ]]; then return $ret else if [[ $n -lt $max ]]; then ((n++)) echo "Failed. Attempt $n/$max..." >&2 sleep $delay; else echo "Command failed after $n attempts." >&2 return $ret fi fi done } debug() { if [[ "${DEBUG}" == 1 ]]; then echo >&2 "$@" fi } # authenticate and get the token getTokenJSON() { # store the whole response with the status at the end HTTP_RESPONSE=$(curl -s -k -w "HTTPSTATUS:%{http_code}" --max-time 10 -X POST -H "Content-Type: application/json" -d "{\"login\":\"guest\",\"pwd\":\"\"}" ${API_BASE_URL}/login) ret=$? if [[ $ret -ne 0 ]]; then return $ret fi # extract the status HTTP_STATUS=$(echo "$HTTP_RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://') # check the status if [[ $HTTP_STATUS -ne 200 ]]; then return 1 else # extract the body HTTP_BODY=$(echo "$HTTP_RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g') echo $HTTP_BODY fi } # extract a value from a JSON structure jsonValue() { KEY=$1 num=$2 awk -F"[,:}]" '{for(i=1;i<=NF;i++){if($i~/\042'$KEY'\042/){print $(i+1)}}}' | tr -d '"' | sed -n ${num}p } stop() { if [[ "$1" == "bootstop" ]]; then echo "STOP esame-get-config-boot" else echo "STOP esame-get-config" fi } # get configuration from WS getConfigVars() { echo "Authenticating to WS..." TOKEN_JSON=`retry getTokenJSON` if [[ "$TOKEN_JSON" == "" ]]; then echo "Authentication failed!" return 2 fi TOKEN=`echo ${TOKEN_JSON} | jsonValue token 1` MACHINE_NAME=`hostname` echo "Getting machine configuration..." MACHINE_JSON=`retry /usr/bin/curl -s -k --max-time 10 -H "Authorization: Bearer ${TOKEN}" -X GET ${API_BASE_URL}/machines/name/${MACHINE_NAME}` MACHINE_ID=`echo $MACHINE_JSON | jsonValue id 1` MACHINE_CONFIGS_ID=`echo $MACHINE_JSON | jsonValue configs_id 1` CONFIG_NAME=`echo $MACHINE_JSON | jsonValue name 2` EXAM_ID=`echo $MACHINE_JSON | jsonValue examid 1` # web service returns "null" if there is no exam # just set an empty string as value if [[ "${EXAM_ID}" == "null" ]]; then EXAM_ID="" fi if [[ "${CONFIG_NAME}" == "" ]]; then echo "Error fetching machine configuration!" return 1 fi MACHINE_CONFIGS_ID_PREV='' CONFIG_NAME_PREV='' if [[ -e /local/config_name ]] then CONFIG_NAME_PREV=`cat /local/config_name` fi } getConfigFile() { echo "Downloading machine config file..." # get configuration file if [[ "${MACHINE_ID}" == "" ]]; then echo "Error downloading config file (machine_id empty, maybe it is not in LabManager's DB)" return 1 fi retry /usr/bin/curl -s -k -o /local/esame-machine.conf --max-time 10 --header "Authorization: Bearer ${TOKEN}" -X GET ${API_BASE_URL}/machines/${MACHINE_ID}/configfile ret=$? if [[ $ret -ne 0 ]]; then echo "Error downloading config file (ret=$ret)" return 1 else echo "Downloaded config file (ret=$ret)" fi } getIpConfigFile() { echo "Downloading machine iptables config file..." # get ipconfig file retry /usr/bin/curl -s -k -o /local/iptables --max-time 10 --header "Authorization: Bearer ${TOKEN}" -X GET ${API_BASE_URL}/machines/${MACHINE_ID}/ipconfigfile ret=$? if [[ $ret -ne 0 ]]; then echo "Error downloading iptables config file (ret=$ret)" return 1 else echo "Downloaded iptables config file (ret=$ret)" fi } updateCurrentConfigId() { # Update this machine's current config id HTTP_STATUS=`/usr/bin/curl -s -k -w "%{http_code}" -o /dev/null --max-time 10 -H "Content-Type: application/json" -H "Authorization: Bearer ${TOKEN}" \ -X PUT -d "{\"current_configs_id\":\"$MACHINE_CONFIGS_ID\"}" ${API_BASE_URL}/machines/${MACHINE_ID}/currentconfig` if [[ $HTTP_STATUS -ne 200 ]] then echo "Error updating current config (http_status=$HTTP_STATUS)" exit 1 else echo "Updated current config (http_status=$HTTP_STATUS)" fi } getConfig() { getConfigVars while [[ $? != 0 ]]; do echo "Error fetching machine info!" echo "If this is a new machine, did you add it into labmanager-admin?" # to repeat until successful, just comment next line return 1 sleep 30 getConfigVars done # back config files up cp -f /local/esame-machine.conf /local/esame-machine.conf.prev >/dev/null 2>&1 cp -f /local/iptables /local/iptables.prev >/dev/null 2>&1 getConfigFile if [[ $? != 0 ]]; then echo "Error fetching machine config file!" return 1 fi getIpConfigFile if [[ $? != 0 ]]; then echo "Error fetching machine iptables file!" return 1 fi return 0 } start() { if [[ "$1" == "boot" ]]; then echo "START esame-get-config-boot" else echo "START esame-get-config" fi getConfig RESULT=$? #echo "TOKEN_JSON: $TOKEN_JSON" #echo "TOKEN: $TOKEN" #echo "MACHINE_NAME: $MACHINE_NAME" #echo "MACHINE_JSON: $MACHINE_JSON" #echo "MACHINE_ID: $MACHINE_ID" #echo "Exam ID: $EXAM_ID" #echo "MACHINE_CONFIGS_ID: $MACHINE_CONFIGS_ID" #echo "MACHINE_CONFIGS_ID_PREV: $MACHINE_CONFIGS_ID_PREV" # any error? if [[ $RESULT != 0 ]]; then if [[ "$1" == "boot" ]]; then echo "Fatal error(s): aborting esame and switching machine to normal state..." # reset and remove exam configuration files echo "$NORMAL_CONFIG_NAME" > /local/config_name echo "" > /local/examid #rm /local/esame-machine.conf >/dev/null 2>&1 #rm /local/esame-machine.conf.prev >/dev/null 2>&1 rm /local/iptables >/dev/null 2>&1 rm /local/iptables.prev >/dev/null 2>&1 rm /local/mk-homedir >/dev/null 2>&1 /usr/bin/systemctl start graphical.target && exit 0 fi echo "Fatal error(s): missing or wrong web service reply, abort." exit 1 fi # extract systemd target name from configuration file # default target on error/empty target ESAME_TARGET="graphical" RES_TARGET=`awk -F= -v key="ESAME_TARGET" '$1==key {print $2}' /local/esame-machine.conf | sed "s/\"//g"` if [[ "${RES_TARGET}" != "" ]]; then ESAME_TARGET=${RES_TARGET} fi # extract ESAME_USBGUARD from configuration file ESAME_USB_GUARD=0 RES_USB_GUARD=`awk -F= -v key="ESAME_USB_GUARD" '$1==key {print $2}' /local/esame-machine.conf | sed "s/\"//g"` if [[ "${RES_USB_GUARD}" != "" ]]; then ESAME_USB_GUARD=${RES_USB_GUARD} fi # extract ESAME_AMQP from configuration file ESAME_AMQP=0 RES_AMQP=`awk -F= -v key="ESAME_AMQP" '$1==key {print $2}' /local/esame-machine.conf | sed "s/\"//g"` if [[ "${RES_AMQP}" != "" ]]; then ESAME_AMQP=${RES_AMQP} fi if [[ -n "${CONFIG_NAME}" ]]; then echo "Configuration: ${CONFIG_NAME}" if [ "${EXAM_ID}" != "" ]; then echo "Exam ID: ${EXAM_ID}" fi if [ "${ESAME_TARGET}" != "" ]; then echo "Systemd Target: ${ESAME_TARGET}" fi fi # the PC is already up and running if [[ "$1" != "boot" ]]; then # get current examid (if any) EXAM_ID_CURRENT="" if [[ -f /local/examid ]]; then EXAM_ID_CURRENT=`cat /local/examid` fi # different examid? if [[ "${EXAM_ID}" != "${EXAM_ID_CURRENT}" ]]; then # reboot => normal if [[ "${EXAM_ID}" == "" ]]; then echo "Reboot to Normal!" # reboot => exam else echo "Reboot to Exam (exam id: ${EXAM_ID})" fi /usr/bin/systemctl reboot fi else # at boot time # update config_name file echo "${CONFIG_NAME}" > /local/config_name # no exam # if [[ "$CONFIG_NAME" == "$NORMAL_CONFIG_NAME" ]]; then if [[ "${EXAM_ID}" == "" ]]; then # remove some files used by exam mode #rm /local/esame-machine.conf >/dev/null 2>&1 #rm /local/esame-machine.conf.prev >/dev/null 2>&1 rm /local/iptables >/dev/null 2>&1 rm /local/iptables.prev >/dev/null 2>&1 rm /local/mk-homedir >/dev/null 2>&1 rm /local/usbguard >/dev/null 2>&1 # this is just cleaned up echo "" > /local/examid else # if the examid of the session before the boot is different, # then clean the exam user home (if the profile requires it) EXAM_ID_PREV="" # if the exam is already started, get examid from file if [[ -f /local/examid ]]; then EXAM_ID_PREV=`cat /local/examid` fi # different examid? if [[ "${EXAM_ID}" != "${EXAM_ID_PREV}" ]]; then # update the file with the current examid echo "${EXAM_ID}" > /local/examid # clean home dir if requested by the profile touch /local/mk-homedir fi if [[ ${ESAME_USB_GUARD} == 1 ]]; then touch /local/usbguard else rm /local/usbguard >/dev/null 2>&1 fi fi # if we use AMQP server, just disable esame-get-config.timer if [[ ${ESAME_AMQP} == 1 ]]; then systemctl disable esame-get-config.timer systemctl stop esame-get-config.timer # otherwise, enable it else systemctl enable esame-get-config.timer systemctl start esame-get-config.timer fi # choose the correct target # we have just booted/rebooted, update the current configuration via web service updateCurrentConfigId systemctl start ${ESAME_TARGET}.target && exit 0 # case "$CONFIG_NAME" in # $NORMAL_CONFIG_NAME) # normal # systemctl start graphical.target && exit 0 # ;; # 'kiosk-dir' | 'kiosk-dir-esami' | 'kiosk-escher' | 'kiosk-freebrowsing' | 'kiosk-teco') # kiosk mode # systemctl start esamekiosk.target && exit 0 # ;; # 'show') # show mode, an exam mode with no limitations on USB ports and network # systemctl start esameshow.target && exit 0 # ;; # *) # all full desktop exams # systemctl start esame.target && exit 0 # ;; # esac fi # Runtime parameters if [[ "$CONFIG_NAME" != "$NORMAL_CONFIG_NAME" ]]; then # check if parameters are changed cmp --silent /local/esame-machine.conf /local/esame-machine.conf.prev if [[ $? -ne 0 ]]; then /usr/bin/systemctl daemon-reload echo "Configuration parameters changed: restart some services... " # restart some exam services #echo -n "USB..." #/usr/bin/systemctl restart esame-usb #echo " done." KIOSK_URL_CHANGED=$(diff /local/esame-machine.conf /local/esame-machine.conf.prev | grep ESAME_KIOSK_URL -c) if [[ $KIOSK_URL_CHANGED -ne 0 ]]; then echo -n "Firefox Home..." FIREFOX_PID=$(pgrep firefox) if [[ "${FIREFOX_PID}" != "" ]]; then FIREFOX_USER=$(ps -o user= -p ${FIREFOX_PID}) rm -f /local/${FIREFOX_USER}/.mozilla/firefox/n3bac2sw.default-release/lock pkill firefox sleep 2 /usr/bin/systemctl restart esame-firefox-home echo " done." # no way to restart firefox, I must miss something :( #echo -n "Restarting Firefox..." #su - ${FIREFOX_USER} -c 'nohup /usr/bin/firefox --display=:0.0 &' #echo " done." else /usr/bin/systemctl restart esame-firefox-home echo " done." fi fi # USBGuard if [[ ${ESAME_USB_GUARD} == 1 ]]; then touch /local/usbguard /usr/bin/systemctl restart usbguard else rm /local/usbguard >/dev/null 2>&1 # this one will not work anyway, as it is applied by kernel, # so it needs a reboot /usr/bin/systemctl stop usbguard fi echo echo "All done." fi fi } args=("$@") case "$1" in 'bootstart') start "boot" ;; 'bootstop') stop "boot" ;; 'start') start ;; 'stop') stop ;; 'restart') stop start ;; *) echo "Usage: $0 { bootstart | bootstop | start | stop | restart }"; exit 1; ;; esac exit 0