Newer
Older

Alberto LIVIO BECCARIA
committed
#!/usr/bin/env -S bash
API_BASE_URL=https://labmanager-api.edu-al.unipmn.it/api/1.0
RETRY_DELAY=5

Alberto LIVIO BECCARIA
committed
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

Alberto LIVIO BECCARIA
committed

Alberto LIVIO BECCARIA
committed
# execute a task and on fail execute it again MAX_RETRY times every RETRY_DELAY seconds

Alberto LIVIO BECCARIA
committed
local n=1
local max=$MAX_RETRY
local delay=$RETRY_DELAY
while true; do
"$@"

Alberto LIVIO BECCARIA
committed
ret=$?
if [[ $ret == 0 ]]; then
return $ret

Alberto LIVIO BECCARIA
committed
else
if [[ $n -lt $max ]]; then
((n++))
echo "Failed. Attempt $n/$max..." >&2
sleep $delay;
else
echo "Command failed after $n attempts." >&2

Alberto LIVIO BECCARIA
committed
return $ret

Alberto LIVIO BECCARIA
committed
fi
fi
done
}
if [[ "${DEBUG}" == 1 ]]; then
echo >&2 "$@"
fi
}

Alberto LIVIO BECCARIA
committed
# authenticate and get the token
getTokenJSON() {

Alberto LIVIO BECCARIA
committed
# 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)

Alberto LIVIO BECCARIA
committed
ret=$?

Alberto LIVIO BECCARIA
committed
if [[ $ret -ne 0 ]]; then

Alberto LIVIO BECCARIA
committed
return $ret
fi

Alberto LIVIO BECCARIA
committed
# extract the status
HTTP_STATUS=$(echo "$HTTP_RESPONSE" | tr -d '\n' | sed -e 's/.*HTTPSTATUS://')
# check the status

Alberto LIVIO BECCARIA
committed
if [[ $HTTP_STATUS -ne 200 ]]; then
return 1

Alberto LIVIO BECCARIA
committed
else

Alberto LIVIO BECCARIA
committed
# extract the body
HTTP_BODY=$(echo "$HTTP_RESPONSE" | sed -e 's/HTTPSTATUS\:.*//g')

Alberto LIVIO BECCARIA
committed
echo $HTTP_BODY
fi

Alberto LIVIO BECCARIA
committed
# extract a value from a JSON structure
awk -F"[,:}]" '{for(i=1;i<=NF;i++){if($i~/\042'$KEY'\042/){print $(i+1)}}}' | tr -d '"' | sed -n ${num}p

Alberto LIVIO BECCARIA
committed
if [[ "$1" == "bootstop" ]]; then
echo "STOP esame-get-config-boot"
else
echo "STOP esame-get-config"
fi

Alberto LIVIO BECCARIA
committed
# get configuration from WS
getConfigVars() {

Alberto LIVIO BECCARIA
committed
echo "Authenticating to WS..."
TOKEN_JSON=`retry getTokenJSON`

Alberto LIVIO BECCARIA
committed
if [[ "$TOKEN_JSON" == "" ]]; then

Alberto LIVIO BECCARIA
committed
echo "Authentication failed!"

Alberto LIVIO BECCARIA
committed
return 2

Alberto LIVIO BECCARIA
committed
fi
TOKEN=`echo ${TOKEN_JSON} | jsonValue token 1`
MACHINE_NAME=`hostname`

Alberto LIVIO BECCARIA
committed
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`

Alberto LIVIO BECCARIA
committed
# 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!"

Alberto LIVIO BECCARIA
committed
return 1
fi
CONFIG_NAME_PREV=''
if [[ -e /local/config_name ]]
CONFIG_NAME_PREV=`cat /local/config_name`
getConfigFile() {

Alberto LIVIO BECCARIA
committed
echo "Downloading machine config file..."
# get configuration file

Alberto LIVIO BECCARIA
committed
if [[ "${MACHINE_ID}" == "" ]]; then
echo "Error downloading config file (machine_id empty, maybe it is not in LabManager's DB)"
return 1
fi

Alberto LIVIO BECCARIA
committed
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)"

Alberto LIVIO BECCARIA
committed
return 1

Alberto LIVIO BECCARIA
committed
echo "Downloaded config file (ret=$ret)"
getIpConfigFile() {

Alberto LIVIO BECCARIA
committed
echo "Downloading machine iptables config file..."
# get ipconfig file

Alberto LIVIO BECCARIA
committed
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)"

Alberto LIVIO BECCARIA
committed
return 1

Alberto LIVIO BECCARIA
committed
echo "Downloaded iptables config file (ret=$ret)"
}
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
}
getConfigVars
while [[ $? != 0 ]]; do
echo "Error fetching machine info!"
echo "If this is a new machine, did you add it into labmanager-admin?"

Alberto LIVIO BECCARIA
committed
# to repeat until successful, just comment next line
return 1
sleep 30
getConfigVars
done

Alberto LIVIO BECCARIA
committed
# back config files up

Alberto LIVIO BECCARIA
committed
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

Alberto LIVIO BECCARIA
committed
if [[ $? != 0 ]]; then
echo "Error fetching machine config file!"

Alberto LIVIO BECCARIA
committed
return 1

Alberto LIVIO BECCARIA
committed
fi

Alberto LIVIO BECCARIA
committed
getIpConfigFile

Alberto LIVIO BECCARIA
committed
if [[ $? != 0 ]]; then
echo "Error fetching machine iptables file!"

Alberto LIVIO BECCARIA
committed
return 1
fi
return 0
}
start() {

Alberto LIVIO BECCARIA
committed
if [[ "$1" == "boot" ]]; then

Alberto LIVIO BECCARIA
committed
echo "START esame-get-config-boot"
else
echo "START esame-get-config"
fi

Alberto LIVIO BECCARIA
committed
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"

Alberto LIVIO BECCARIA
committed
#echo "MACHINE_CONFIGS_ID: $MACHINE_CONFIGS_ID"
#echo "MACHINE_CONFIGS_ID_PREV: $MACHINE_CONFIGS_ID_PREV"

Alberto LIVIO BECCARIA
committed

Alberto LIVIO BECCARIA
committed
if [[ $RESULT != 0 ]]; then

Alberto LIVIO BECCARIA
committed
if [[ "$1" == "boot" ]]; then

Alberto LIVIO BECCARIA
committed
echo "Fatal error(s): aborting esame and switching machine to normal state..."

Alberto LIVIO BECCARIA
committed
# 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

Alberto LIVIO BECCARIA
committed
rm /local/iptables >/dev/null 2>&1
rm /local/iptables.prev >/dev/null 2>&1

Alberto LIVIO BECCARIA
committed
rm /local/mk-homedir >/dev/null 2>&1

Alberto LIVIO BECCARIA
committed
/usr/bin/systemctl start graphical.target && exit 0

Alberto LIVIO BECCARIA
committed
fi

Alberto LIVIO BECCARIA
committed
echo "Fatal error(s): missing or wrong web service reply, abort."
exit 1

Alberto LIVIO BECCARIA
committed
fi
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
# 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

Alberto LIVIO BECCARIA
committed
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

Alberto LIVIO BECCARIA
committed
echo "${CONFIG_NAME}" > /local/config_name

Alberto LIVIO BECCARIA
committed
# 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

Alberto LIVIO BECCARIA
committed
rm /local/iptables >/dev/null 2>&1
rm /local/iptables.prev >/dev/null 2>&1

Alberto LIVIO BECCARIA
committed
rm /local/mk-homedir >/dev/null 2>&1
rm /local/usbguard >/dev/null 2>&1
# this is just cleaned up
echo "" > /local/examid
# 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
# 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
# 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
# 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

Alberto LIVIO BECCARIA
committed
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

Alberto LIVIO BECCARIA
committed
'bootstart')
start "boot"
;;

Alberto LIVIO BECCARIA
committed
'bootstop')
stop "boot"
;;
stop
start
;;

Alberto LIVIO BECCARIA
committed
echo "Usage: $0 { bootstart | bootstop | start | stop | restart }";
exit 1;
;;