se adecua el servicio
This commit is contained in:
parent
87e5c80a91
commit
0ab5b4f68c
@ -2,9 +2,14 @@
|
|||||||
# postinst script for EmaLibre
|
# postinst script for EmaLibre
|
||||||
set -e
|
set -e
|
||||||
printf "\033[1;4m3) Se aplican los permisos necesarios.\033[0m"
|
printf "\033[1;4m3) Se aplican los permisos necesarios.\033[0m"
|
||||||
chmod -R 777 /usr/share/emalibre
|
if [ -d /usr/share/emalibre/gui_web ]; then
|
||||||
|
# El servicio corre como root: sus fuentes no deben ser editables por todos.
|
||||||
|
chmod -R u+rwX,go+rX,go-w /usr/share/emalibre
|
||||||
|
else
|
||||||
|
chmod -R 777 /usr/share/emalibre
|
||||||
|
fi
|
||||||
chmod a-x /usr/share/menu/emalibre
|
chmod a-x /usr/share/menu/emalibre
|
||||||
chmod 777 /usr/share/applications/emalibre.desktop
|
chmod 644 /usr/share/applications/emalibre.desktop
|
||||||
printf "\033[1;32m --> OK. \033[0m\n"
|
printf "\033[1;32m --> OK. \033[0m\n"
|
||||||
printf "\033[1;4m4) Se actualizan los menus del sistema.\033[0m"
|
printf "\033[1;4m4) Se actualizan los menus del sistema.\033[0m"
|
||||||
if [ "$1" = "configure" ] && [ -x /usr/bin/update-menus ]; then update-menus ; fi
|
if [ "$1" = "configure" ] && [ -x /usr/bin/update-menus ]; then update-menus ; fi
|
||||||
@ -16,7 +21,7 @@ if [ -f "/tmp/ConfiguracionGeneral.js" ]; then
|
|||||||
printf "\033[1;4m6) Se restaura el archivo de configuracion.\033[0m"
|
printf "\033[1;4m6) Se restaura el archivo de configuracion.\033[0m"
|
||||||
if [ -d "/usr/share/emalibre/conf/" ]; then
|
if [ -d "/usr/share/emalibre/conf/" ]; then
|
||||||
mv -f /tmp/ConfiguracionGeneral.js /usr/share/emalibre/conf/
|
mv -f /tmp/ConfiguracionGeneral.js /usr/share/emalibre/conf/
|
||||||
chmod 777 /usr/share/emalibre/conf/ConfiguracionGeneral.js || true
|
chmod 644 /usr/share/emalibre/conf/ConfiguracionGeneral.js || true
|
||||||
printf "\033[1;32m --> OK. \033[0m\n"
|
printf "\033[1;32m --> OK. \033[0m\n"
|
||||||
elif [ -d "/usr/share/emalibre/package.nw/conf/" ]; then
|
elif [ -d "/usr/share/emalibre/package.nw/conf/" ]; then
|
||||||
mv -f /tmp/ConfiguracionGeneral.js /usr/share/emalibre/package.nw/conf/
|
mv -f /tmp/ConfiguracionGeneral.js /usr/share/emalibre/package.nw/conf/
|
||||||
@ -34,4 +39,11 @@ else
|
|||||||
printf "\033[1;36m --> /usr/share/emalibre/conf/ConfiguracionGeneral.js. \033[0m\n"
|
printf "\033[1;36m --> /usr/share/emalibre/conf/ConfiguracionGeneral.js. \033[0m\n"
|
||||||
echo ""
|
echo ""
|
||||||
fi
|
fi
|
||||||
|
if [ "$1" = configure ] && [ -x /etc/init.d/emalibre ]; then
|
||||||
|
update-rc.d emalibre defaults
|
||||||
|
if [ -d /run/systemd/system ]; then
|
||||||
|
systemctl daemon-reload
|
||||||
|
fi
|
||||||
|
invoke-rc.d emalibre start
|
||||||
|
fi
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
@ -1,4 +1,12 @@
|
|||||||
#!/bin/sh
|
#!/bin/sh
|
||||||
set -e
|
set -e
|
||||||
echo "Se actualiza los menus y reglas de control..."
|
case "$1" in
|
||||||
if [ "$1" = "configure" ] && [ -x /usr/bin/update-menus ]; then update-menus ; fi
|
remove|purge)
|
||||||
|
if [ -x /usr/bin/update-menus ]; then update-menus; fi
|
||||||
|
if [ -d /run/systemd/system ]; then systemctl daemon-reload; fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
if [ "$1" = purge ] && [ ! -e /etc/init.d/emalibre ]; then
|
||||||
|
update-rc.d emalibre remove
|
||||||
|
fi
|
||||||
|
exit 0
|
||||||
|
|||||||
@ -6,8 +6,6 @@
|
|||||||
# * <new-preinst> `upgrade' <old-version>
|
# * <new-preinst> `upgrade' <old-version>
|
||||||
# * <old-preinst> `abort-upgrade' <new-version>
|
# * <old-preinst> `abort-upgrade' <new-version>
|
||||||
set -e
|
set -e
|
||||||
pidFile="/var/run/emalibre.pid"
|
|
||||||
pidMonitorFile="/var/run/monitor_emalibre.pid"
|
|
||||||
echo ""
|
echo ""
|
||||||
printf "\033[1;35m***************************************************************\n"
|
printf "\033[1;35m***************************************************************\n"
|
||||||
printf "Gracias por instalar EMA Libre Cliente (Carpincho)!!.\n"
|
printf "Gracias por instalar EMA Libre Cliente (Carpincho)!!.\n"
|
||||||
@ -19,14 +17,31 @@ case "$1" in
|
|||||||
|
|
||||||
printf "\033[1;10m * 1.0) Se verifica y detiene si existe EMA Libre corriendo.\033[0m"
|
printf "\033[1;10m * 1.0) Se verifica y detiene si existe EMA Libre corriendo.\033[0m"
|
||||||
# 0. Se detiene emalibre si existe instancia corriendo.
|
# 0. Se detiene emalibre si existe instancia corriendo.
|
||||||
if [ -f $pidFile ]; then
|
# Versiones anteriores usaban stopall y borraban el PID sin parar.
|
||||||
rm -f /var/run/emalibre.pid
|
# Detener únicamente EMA_Web, incluso durante la primera migración.
|
||||||
rm -f /var/run/emalibre.log
|
if [ -f /usr/share/emalibre/node_modules/forever/lib/forever.js ]; then
|
||||||
fi
|
NODE=/usr/share/emalibre/node_modules/node/bin/node
|
||||||
if [ -f $pidMonitorFile ]; then
|
# Compatibilidad al actualizar una instalación antigua sin runtime incluido.
|
||||||
rm -f /var/run/monitor_emalibre.pid
|
if [ ! -x "$NODE" ]; then
|
||||||
rm -f /var/run/monitor_emalibre.log
|
NODE=$(command -v node || true)
|
||||||
fi
|
fi
|
||||||
|
if [ -z "$NODE" ] || [ ! -x "$NODE" ]; then
|
||||||
|
echo "No se encontró Node para detener la instalación anterior." >&2
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
HOME=/root FOREVER_ROOT=/root/.forever "$NODE" - <<'JS'
|
||||||
|
const forever = require('/usr/share/emalibre/node_modules/forever');
|
||||||
|
const timer = setTimeout(() => process.exit(1), 15000);
|
||||||
|
forever.list(false, (err, processes) => {
|
||||||
|
if (err) { console.error(err); process.exit(1); }
|
||||||
|
if (!(processes || []).some(p => p.uid === 'EMA_Web')) {
|
||||||
|
clearTimeout(timer); process.exit(0);
|
||||||
|
}
|
||||||
|
forever.stop('EMA_Web').on('stop', () => process.exit(0))
|
||||||
|
.on('error', err => { console.error(err); process.exit(1); });
|
||||||
|
});
|
||||||
|
JS
|
||||||
|
fi
|
||||||
printf "\033[1;32m --> OK. \033[0m\n"
|
printf "\033[1;32m --> OK. \033[0m\n"
|
||||||
# 1. Se consulta si existe el archivo de configuracion
|
# 1. Se consulta si existe el archivo de configuracion
|
||||||
if [ -f "/usr/share/emalibre/conf/ConfiguracionGeneral.js" ]; then
|
if [ -f "/usr/share/emalibre/conf/ConfiguracionGeneral.js" ]; then
|
||||||
|
|||||||
10
build/Deb64/DEBIAN/prerm
Executable file
10
build/Deb64/DEBIAN/prerm
Executable file
@ -0,0 +1,10 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
set -e
|
||||||
|
case "$1" in
|
||||||
|
remove|upgrade|deconfigure)
|
||||||
|
if [ -x /etc/init.d/emalibre ]; then
|
||||||
|
invoke-rc.d emalibre stop
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
exit 0
|
||||||
@ -1,207 +1,159 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
### BEGIN INIT INFO
|
### BEGIN INIT INFO
|
||||||
# Provides: EMA Libre Carpincho
|
# Provides: emalibre
|
||||||
# Required-Start: $syslog
|
# Required-Start: $remote_fs $network $syslog
|
||||||
# Required-Stop: $syslog
|
# Required-Stop: $remote_fs $network $syslog
|
||||||
# Default-Start: 2 3 4 5
|
# Default-Start: 2 3 4 5
|
||||||
# Default-Stop: 0 1 6
|
# Default-Stop: 0 1 6
|
||||||
# Short-Description: EMA Libre Carpincho demonio
|
# Short-Description: EMA Libre Carpincho web
|
||||||
# Description: Start/stop/Restart EMA Libre Carpincho
|
|
||||||
### END INIT INFO
|
### END INIT INFO
|
||||||
|
|
||||||
### CONFIG ZONE
|
PATH=/usr/sbin:/usr/bin:/sbin:/bin
|
||||||
# Get function from functions library
|
export PATH
|
||||||
#set -e
|
|
||||||
. /lib/lsb/init-functions
|
. /lib/lsb/init-functions
|
||||||
|
|
||||||
RETVAL=0
|
appFilePath=/usr/share/emalibre
|
||||||
|
pidFile=/run/emalibre.pid
|
||||||
# Nombre del servicio.
|
logDir=/var/log/emalibre
|
||||||
serviceName="emalibre"
|
modeFile=/etc/emalibre_modo
|
||||||
|
|
||||||
# Ubicacion de la APP
|
|
||||||
appFilePath="/usr/share/emalibre"
|
|
||||||
|
|
||||||
# Archivo de Inicio.
|
|
||||||
web="gui_web/express.js"
|
|
||||||
|
|
||||||
### END CONFIG ZONE
|
|
||||||
|
|
||||||
# Ubicacion de logs y del pid.
|
|
||||||
pidFile="/var/run/$serviceName.pid"
|
|
||||||
logFile="/var/run/$serviceName.log"
|
|
||||||
|
|
||||||
# Ubicacion de node como modulo de carpincho.
|
|
||||||
nodemodule="$appFilePath/node_modules/node/bin"
|
|
||||||
|
|
||||||
# Ubicacion de forever como modulo de carpincho.
|
|
||||||
foreverApp="$appFilePath/node_modules/forever/bin/forever"
|
foreverApp="$appFilePath/node_modules/forever/bin/forever"
|
||||||
|
# Mantener el registro de instalaciones anteriores iniciadas como root.
|
||||||
|
export HOME=/root
|
||||||
|
export FOREVER_ROOT=/root/.forever
|
||||||
|
nodeBin="$appFilePath/node_modules/node/bin/node"
|
||||||
|
export PATH="$appFilePath/node_modules/node/bin:$PATH"
|
||||||
|
|
||||||
# Ubicacion de logs de EMA Libre
|
fail() { echo "emalibre: $*" >&2; return 1; }
|
||||||
emaLogs="$appFilePath/logs/debug.log"
|
require_root() {
|
||||||
|
[ "$(id -u)" -eq 0 ] || { fail "Este comando requiere root."; return 4; }
|
||||||
export PATH=$PATH:$nodemodule
|
}
|
||||||
|
check_runtime() {
|
||||||
|
[ -x "$nodeBin" ] || { fail "Falta el Node incluido en $nodeBin (Node.js >= 20)."; return 5; }
|
||||||
|
"$nodeBin" -e 'process.exit(Number(process.versions.node.split(".")[0]) >= 20 ? 0 : 1)' || {
|
||||||
|
fail "Se requiere Node.js >= 20."; return 5;
|
||||||
|
}
|
||||||
|
[ -f "$foreverApp" ] && [ -f "$appFilePath/gui_web/express.js" ] || {
|
||||||
|
fail "La instalación web está incompleta."; return 5;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
node_run() { "$nodeBin" "$@" 9>&-; }
|
||||||
|
forever_cmd() { node_run "$foreverApp" "$@"; }
|
||||||
|
# Consultar el supervisor, sin confiar en archivos PID residuales.
|
||||||
|
# 0: activo; 3: detenido; 4: no se pudo consultar.
|
||||||
|
process_status() {
|
||||||
|
"$nodeBin" - "$appFilePath" <<'JS'
|
||||||
|
const root = process.argv[2];
|
||||||
|
const timer = setTimeout(() => process.exit(4), 5000);
|
||||||
|
try {
|
||||||
|
require(root + '/node_modules/forever').list(false, (err, processes) => {
|
||||||
|
clearTimeout(timer);
|
||||||
|
if (err) { console.error(err.message); process.exit(4); }
|
||||||
|
const active = (processes || []).some(p => p.uid === 'EMA_Web');
|
||||||
|
process.exit(active ? 0 : 3);
|
||||||
|
});
|
||||||
|
} catch (err) { console.error(err.message); process.exit(4); }
|
||||||
|
JS
|
||||||
|
}
|
||||||
start() {
|
start() {
|
||||||
if [ ! -f /etc/emalibre_modo ]
|
local state mode
|
||||||
then
|
process_status; state=$?
|
||||||
`echo "web" > /etc/emalibre_modo`
|
case "$state" in
|
||||||
fi
|
0) echo "EMA Libre ya está ejecutándose."; return 0 ;;
|
||||||
MODO=`cat /etc/emalibre_modo`
|
3) ;;
|
||||||
if [ -f $pidFile ]; then
|
*) fail "No se pudo consultar Forever."; return "$state" ;;
|
||||||
log_daemon_msg "EMA libre Carpincho se encuentra corriendo."
|
esac
|
||||||
RETVAL=$?
|
if [ ! -f "$modeFile" ]; then
|
||||||
else
|
printf 'web\n' > "$modeFile" || return 1
|
||||||
if [ $MODO = 'web' ]
|
fi
|
||||||
then
|
mode=$(tr -d '[:space:]' < "$modeFile") || return 1
|
||||||
log_daemon_msg "Comenzando EMA Libre Carpincho en modo web"
|
[ "$mode" = web ] || { fail "Modo inválido: '$mode'; se esperaba web."; return 2; }
|
||||||
echo "$(date '+%d/%m/%Y %H:%M:%S') - 0|SERVICIO|Inicio el servicio en modo web." >> $emaLogs
|
mkdir -p "$logDir" || return 1
|
||||||
$foreverApp start --uid "EMA_Web" --id "EMA_Web" --minUptime 5000 --spinSleepTime 5000 --sourceDir $appFilePath --workingDir $appFilePath --pidFile $pidFile -l $logFile -a -d -c node "$web" iniciar
|
rm -f "$pidFile" || return 1
|
||||||
RETVAL=$?
|
# Forever concatena sourceDir y script: el script debe ser relativo.
|
||||||
fi
|
forever_cmd start --uid EMA_Web --id EMA_Web --minUptime 5000 --spinSleepTime 5000 \
|
||||||
fi
|
--sourceDir "$appFilePath" --workingDir "$appFilePath" --pidFile "$pidFile" \
|
||||||
RETVAL=$?
|
-l "$logDir/forever.log" -o "$logDir/stdout.log" -e "$logDir/stderr.log" \
|
||||||
|
-a -c "$nodeBin" "gui_web/express.js" iniciar || return $?
|
||||||
|
# Forever arranca en segundo plano: esperar a que registre el supervisor.
|
||||||
|
local attempt
|
||||||
|
for attempt in {1..10}; do
|
||||||
|
process_status; state=$?
|
||||||
|
[ "$state" -eq 0 ] && { echo "EMA Libre iniciado."; return 0; }
|
||||||
|
[ "$state" -eq 3 ] || return "$state"
|
||||||
|
sleep 1
|
||||||
|
done
|
||||||
|
fail "El supervisor no arrancó; revise $logDir."
|
||||||
}
|
}
|
||||||
|
|
||||||
restart() {
|
|
||||||
log_daemon_msg "Reiniciando EMA Libre Carpincho"
|
|
||||||
echo "$(date '+%d/%m/%Y %H:%M:%S') - 0|SERVICIO|Reiniciando el servicio." >> $emaLogs
|
|
||||||
$foreverApp restart $nodemodule
|
|
||||||
RETVAL=$?
|
|
||||||
}
|
|
||||||
|
|
||||||
stop() {
|
stop() {
|
||||||
if [ -f $pidFile ]; then
|
local state
|
||||||
log_daemon_msg "Deteniendo EMA Libre Carpincho."
|
process_status; state=$?
|
||||||
echo "$(date '+%d/%m/%Y %H:%M:%S') - 0|SERVICIO|Detenido el servicio." >> $emaLogs
|
case "$state" in
|
||||||
$foreverApp stopall
|
0) forever_cmd stop EMA_Web || return $? ;;
|
||||||
RETVAL=$?
|
3) echo "EMA Libre ya está detenido." ;;
|
||||||
else
|
*) fail "No se pudo consultar Forever."; return "$state" ;;
|
||||||
log_daemon_msg "EMA libre Carpincho no se encuentra ejecutandose."
|
esac
|
||||||
fi
|
process_status; state=$?
|
||||||
RETVAL=$?
|
[ "$state" -eq 3 ] || { fail "No se pudo confirmar la parada."; return 1; }
|
||||||
|
rm -f "$pidFile"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
status() {
|
status() {
|
||||||
log_daemon_msg "Mostrando estado nativo del servicio."
|
local state
|
||||||
RETVAL=$?
|
process_status; state=$?
|
||||||
|
case "$state" in
|
||||||
|
0) echo "EMA Libre: supervisor activo." ;;
|
||||||
|
3) echo "EMA Libre: detenido." ;;
|
||||||
|
*) fail "Estado desconocido; no se pudo consultar Forever." ;;
|
||||||
|
esac
|
||||||
|
return "$state"
|
||||||
|
}
|
||||||
|
set_boot() {
|
||||||
|
# El arranque del servicio es independiente del inicio del recolector.
|
||||||
|
if [ -d /run/systemd/system ]; then
|
||||||
|
systemctl "$1" emalibre
|
||||||
|
else
|
||||||
|
update-rc.d emalibre defaults && update-rc.d emalibre "$1"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
view_conf() {
|
||||||
|
printf 'Modo: '; cat "$modeFile" || return 1
|
||||||
|
if [ -d /run/systemd/system ]; then
|
||||||
|
systemctl is-enabled emalibre
|
||||||
|
else
|
||||||
|
echo 'Inicio del servicio: consultar enlaces /etc/rc[2-5].d/*emalibre'
|
||||||
|
fi
|
||||||
|
"$nodeBin" - "$appFilePath/conf/ConfiguracionGeneral.js" <<'JS'
|
||||||
|
const cfg = require(process.argv[2]).ConfGeneral;
|
||||||
|
for (const key of ['Tiempo_de_Recoleccion', 'UTC', 'SistemaMetrico', 'debug',
|
||||||
|
'debugTamanio', 'NombreEstacion', 'Modo', 'inicio_automatico', 'Audio',
|
||||||
|
'notificar_cambios', 'audioVoces', 'IP', 'Puerto', 'Ruta']) {
|
||||||
|
console.log(key + ': ' + cfg[key]);
|
||||||
|
}
|
||||||
|
JS
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case "${1:-}" in
|
||||||
uptime() {
|
start|stop|restart|force-reload|status|uptime|reporte|view-conf|set-inicio-enabled|set-inicio-disable) ;;
|
||||||
echo "$(date '+%d/%m/%Y %H:%M:%S') - 0|SERVICIO|Mostrando el uptime del servicio (consola)." >> $emaLogs
|
*) echo "Uso: $0 {start|stop|restart|force-reload|status|uptime|reporte|view-conf|set-inicio-enabled|set-inicio-disable}" >&2; exit 2 ;;
|
||||||
$foreverApp list
|
esac
|
||||||
RETVAL=$?
|
require_root || exit $?
|
||||||
}
|
check_runtime || exit $?
|
||||||
|
case "$1" in
|
||||||
reporte() {
|
start|stop|restart|force-reload|set-inicio-enabled|set-inicio-disable)
|
||||||
echo "$(date '+%d/%m/%Y %H:%M:%S') - 0|SERVICIO|Mostrando el reporte de consola." >> $emaLogs
|
# Evitar arranques/paradas simultáneos. Cerrar el descriptor en Node
|
||||||
pushd "$appFilePath"
|
# impide que el daemon herede y retenga el bloqueo.
|
||||||
"$nodemodule/node" core/reporte.js
|
exec 9>/run/lock/emalibre.lock || exit 1
|
||||||
RETVAL=$?
|
flock -w 30 9 || exit 1
|
||||||
}
|
;;
|
||||||
|
esac
|
||||||
if [ -d /usr/share/emalibre/gui_web ]
|
case "$1" in
|
||||||
then
|
start) start ;;
|
||||||
# SI EXISTE EL MODULO GUI_WEB se habilitan algunas opciones
|
stop) stop ;;
|
||||||
case "$1" in
|
restart|force-reload) stop && start ;;
|
||||||
start)
|
status) status ;;
|
||||||
start
|
uptime) forever_cmd list ;;
|
||||||
|
reporte) (cd "$appFilePath" && node_run core/reporte.js) ;;
|
||||||
;;
|
view-conf) view_conf ;;
|
||||||
stop)
|
set-inicio-enabled) set_boot enable ;;
|
||||||
stop
|
set-inicio-disable) set_boot disable ;;
|
||||||
|
esac
|
||||||
;;
|
exit $?
|
||||||
status)
|
|
||||||
status
|
|
||||||
|
|
||||||
;;
|
|
||||||
restart)
|
|
||||||
restart
|
|
||||||
|
|
||||||
;;
|
|
||||||
reporte)
|
|
||||||
reporte
|
|
||||||
|
|
||||||
;;
|
|
||||||
uptime)
|
|
||||||
uptime
|
|
||||||
|
|
||||||
;;
|
|
||||||
set-inicio-enabled)
|
|
||||||
log_daemon_msg "Se Habilito el servicio para inicio automatico."
|
|
||||||
systemctl enable emalibre
|
|
||||||
"$nodemodule/node" -e "
|
|
||||||
const fs = require('fs');
|
|
||||||
const cfgPath = '/usr/share/emalibre/conf/ConfiguracionGeneral.js';
|
|
||||||
const cfg = require(cfgPath);
|
|
||||||
cfg.ConfGeneral.inicio_automatico = true;
|
|
||||||
fs.writeFileSync(
|
|
||||||
cfgPath,
|
|
||||||
'module.exports = ' + JSON.stringify(cfg, null, 2) + ';\n'
|
|
||||||
);
|
|
||||||
"
|
|
||||||
|
|
||||||
;;
|
|
||||||
set-inicio-disable)
|
|
||||||
log_daemon_msg "Se Deshabilito el inicio automatico del servicio."
|
|
||||||
systemctl disable emalibre
|
|
||||||
"$nodemodule/node" -e "
|
|
||||||
const fs = require('fs');
|
|
||||||
const cfgPath = '/usr/share/emalibre/conf/ConfiguracionGeneral.js';
|
|
||||||
const cfg = require(cfgPath);
|
|
||||||
cfg.ConfGeneral.inicio_automatico = false;
|
|
||||||
fs.writeFileSync(
|
|
||||||
cfgPath,
|
|
||||||
'module.exports = ' + JSON.stringify(cfg, null, 2) + ';\n'
|
|
||||||
);
|
|
||||||
"
|
|
||||||
;;
|
|
||||||
view-conf)
|
|
||||||
log_daemon_msg "Configuración de EMA Libre Carpincho"
|
|
||||||
log_daemon_msg "-------------------------------------"
|
|
||||||
CFG=/usr/share/emalibre/conf/ConfiguracionGeneral.js
|
|
||||||
if [ -f /etc/emalibre_modo ]
|
|
||||||
then
|
|
||||||
log_daemon_msg "Modo actual: `cat /etc/emalibre_modo` "
|
|
||||||
else
|
|
||||||
`echo "consola" > /etc/emalibre_modo`
|
|
||||||
log_daemon_msg "Modo actual: `cat /etc/emalibre_modo` "
|
|
||||||
fi
|
|
||||||
log_daemon_msg "Inicio Automatico (servicio): `systemctl is-enabled emalibre 2> echo`"
|
|
||||||
log_daemon_msg ""
|
|
||||||
log_daemon_msg "----------------------"
|
|
||||||
log_daemon_msg "Configuracion Global:"
|
|
||||||
log_daemon_msg "->`grep "Version" /usr/share/emalibre/conf/ConfiguracionGlobal.js`"
|
|
||||||
log_daemon_msg "->`grep "Nombre" /usr/share/emalibre/conf/ConfiguracionGlobal.js`"
|
|
||||||
log_daemon_msg "----------------------"
|
|
||||||
log_daemon_msg "Configuracion General:"
|
|
||||||
log_daemon_msg ""
|
|
||||||
CFG=/usr/share/emalibre/conf/ConfiguracionGeneral.js
|
|
||||||
log_daemon_msg "-> Tiempo de Recolección: $(sed -nE 's/^[[:space:]]*"Tiempo_de_Recoleccion"[[:space:]]*:[[:space:]]*([0-9]+),?/\1/p' $CFG)"
|
|
||||||
log_daemon_msg "-> UTC: $(sed -nE 's/^[[:space:]]*"UTC"[[:space:]]*:[[:space:]]*(-?[0-9]+),?/\1/p' $CFG)"
|
|
||||||
log_daemon_msg "-> Sistema Métrico: $(sed -nE 's/^[[:space:]]*"SistemaMetrico"[[:space:]]*:[[:space:]]*"([^"]+)",?/\1/p' $CFG)"
|
|
||||||
log_daemon_msg "-> Nivel Debug: $(sed -nE 's/^[[:space:]]*"debug"[[:space:]]*:[[:space:]]*([0-9]+),?/\1/p' $CFG)"
|
|
||||||
log_daemon_msg "-> Tamaño Debug: $(sed -nE 's/^[[:space:]]*"debugTamanio"[[:space:]]*:[[:space:]]*([0-9]+),?/\1/p' $CFG)"
|
|
||||||
log_daemon_msg "-> Nombre Estación: $(sed -nE 's/^[[:space:]]*"NombreEstacion"[[:space:]]*:[[:space:]]*"([^"]+)",?/\1/p' $CFG)"
|
|
||||||
log_daemon_msg "-> Modo: $(sed -nE 's/^[[:space:]]*"Modo"[[:space:]]*:[[:space:]]*"([^"]+)",?/\1/p' $CFG)"
|
|
||||||
log_daemon_msg "-> Llave R: $(sed -nE 's/^[[:space:]]*"Llave_R"[[:space:]]*:[[:space:]]*"([^"]+)",?/\1/p' $CFG)"
|
|
||||||
log_daemon_msg "-> Inicio automático: $(sed -nE 's/^[[:space:]]*"inicio_automatico"[[:space:]]*:[[:space:]]*(true|false),?/\1/p' $CFG)"
|
|
||||||
log_daemon_msg "-> Audio: $(sed -nE 's/^[[:space:]]*"Audio"[[:space:]]*:[[:space:]]*(true|false),?/\1/p' $CFG)"
|
|
||||||
log_daemon_msg "-> Notificar cambios: $(sed -nE 's/^[[:space:]]*"notificar_cambios"[[:space:]]*:[[:space:]]*(true|false),?/\1/p' $CFG)"
|
|
||||||
log_daemon_msg "-> Audio Voces: $(sed -nE 's/^[[:space:]]*"audioVoces"[[:space:]]*:[[:space:]]*"([^"]+)",?/\1/p' $CFG)"
|
|
||||||
log_daemon_msg "-> IP: $(sed -nE 's/^[[:space:]]*"IP"[[:space:]]*:[[:space:]]*"([^"]+)",?/\1/p' $CFG)"
|
|
||||||
log_daemon_msg "-> Puerto: $(sed -nE 's/^[[:space:]]*"Puerto"[[:space:]]*:[[:space:]]*"([^"]+)",?/\1/p' $CFG)"
|
|
||||||
log_daemon_msg "-> Ruta: $(sed -nE 's/^[[:space:]]*"Ruta"[[:space:]]*:[[:space:]]*"([^"]+)",?/\1/p' $CFG)"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
echo "Utilice: {start|stop|status|restart|set-inicio-enabled|set-inicio-disable|view-conf|reporte|uptime}"
|
|
||||||
exit 1
|
|
||||||
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
fi
|
|
||||||
|
|
||||||
exit $RETVAL
|
|
||||||
|
|||||||
@ -5,7 +5,7 @@ Priority: optional
|
|||||||
Section: utils
|
Section: utils
|
||||||
Maintainer: Laboratorio de Investigacion Gugler <gugler_contacto@uader.edu.ar>
|
Maintainer: Laboratorio de Investigacion Gugler <gugler_contacto@uader.edu.ar>
|
||||||
Homepage: https://ema.gugler.com.ar
|
Homepage: https://ema.gugler.com.ar
|
||||||
Depends: nodejs (>= 14), libusb-1.0-0, libudev1
|
Depends: lsb-base, init-system-helpers, util-linux, libusb-1.0-0, libudev1
|
||||||
Conflicts: emalibre-gui
|
Conflicts: emalibre-gui
|
||||||
Description: EMA Libre Cliente (Carpincho)
|
Description: EMA Libre Cliente (Carpincho)
|
||||||
Software Libre en modo web y consola para Estaciones Meteorológicas Automáticas.
|
Software Libre en modo web y consola para Estaciones Meteorológicas Automáticas.
|
||||||
|
|||||||
@ -5,7 +5,7 @@ Priority: optional
|
|||||||
Section: application
|
Section: application
|
||||||
Maintainer: Laboratorio de Investigacion Gugler <gugler_contacto@uader.edu.ar>
|
Maintainer: Laboratorio de Investigacion Gugler <gugler_contacto@uader.edu.ar>
|
||||||
Homepage: https://ema.gugler.com.ar
|
Homepage: https://ema.gugler.com.ar
|
||||||
Depends:
|
Depends: lsb-base, init-system-helpers, util-linux, libusb-1.0-0, libudev1
|
||||||
Conflicts: emalibre-gui
|
Conflicts: emalibre-gui
|
||||||
Description: EMA Libre Cliente (Carpincho) - Software Libre en modo web y consola para Estaciones Meteorológica Automáticas.
|
Description: EMA Libre Cliente (Carpincho) - Software Libre en modo web y consola para Estaciones Meteorológica Automáticas.
|
||||||
EMA Libre es Libre y Gratuito desarrollado por el Laboratorio de Investigación Gugler
|
EMA Libre es Libre y Gratuito desarrollado por el Laboratorio de Investigación Gugler
|
||||||
|
|||||||
@ -48,6 +48,12 @@ function spinner() {
|
|||||||
printf " \b\b\b\b"
|
printf " \b\b\b\b"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# El entorno de compilación requiere Node 20; el DEB incluye su propio runtime.
|
||||||
|
if ! node -e 'process.exit(Number(process.versions.node.split(".")[0]) >= 20 ? 0 : 1)'; then
|
||||||
|
log_error "Se requiere Node.js >= 20 para construir el paquete web."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
# =======================
|
# =======================
|
||||||
# VERSIONES
|
# VERSIONES
|
||||||
# =======================
|
# =======================
|
||||||
@ -70,7 +76,7 @@ echo ""
|
|||||||
# LIMPIEZA Y PREPARACIÓN
|
# LIMPIEZA Y PREPARACIÓN
|
||||||
# =======================
|
# =======================
|
||||||
log_info "1) Limpiando compilación anterior."
|
log_info "1) Limpiando compilación anterior."
|
||||||
mkdir -p "$DEB_DIR/usr/bin" "$DEB_DIR/usr/share/emalibre" "$DEBS_OUT"
|
mkdir -p "$DEB_DIR/usr/bin" "$DEB_DIR/usr/share/emalibre" "$DEBS_OUT" "$TMP_DIR"
|
||||||
sudo rm -rf "$EMALIBRE_DIR"/* "$TMP_DIR/emalibre_nogui" "$DEB_DIR/usr/bin/"* "$DEB_DIR/usr/share/emalibre/"*
|
sudo rm -rf "$EMALIBRE_DIR"/* "$TMP_DIR/emalibre_nogui" "$DEB_DIR/usr/bin/"* "$DEB_DIR/usr/share/emalibre/"*
|
||||||
log_ok " --> OK."
|
log_ok " --> OK."
|
||||||
|
|
||||||
@ -134,7 +140,21 @@ log_ok " --> OK."
|
|||||||
|
|
||||||
log_info "7) Generando node_modules con NPM del proyecto."
|
log_info "7) Generando node_modules con NPM del proyecto."
|
||||||
cd "$EMALIBRE_DIR/package.nw"
|
cd "$EMALIBRE_DIR/package.nw"
|
||||||
npm ci --only=production --no-audit --silent 2>>"$LOG_FILE" 1>/dev/null
|
# El lockfile no está versionado: sincronizarlo con package.json antes de npm ci.
|
||||||
|
npm install --package-lock-only --ignore-scripts --no-audit --silent 2>>"$LOG_FILE" 1>/dev/null
|
||||||
|
npm ci --omit=dev --no-audit --silent 2>>"$LOG_FILE" 1>/dev/null
|
||||||
|
# npm instala el binario de Node para la arquitectura de compilación dentro del paquete.
|
||||||
|
BUNDLED_NODE="$PWD/node_modules/node/bin/node"
|
||||||
|
if [ ! -x "$BUNDLED_NODE" ] || ! "$BUNDLED_NODE" -e '
|
||||||
|
const expected = require("./package.json").dependencies.node;
|
||||||
|
process.exit(process.versions.node === expected && process.platform === "linux" && process.arch === "x64" ? 0 : 1);
|
||||||
|
'; then
|
||||||
|
log_error "Falta el runtime Node incluido o no corresponde a la versión/arquitectura del DEB."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
# Compilar/cargar las dependencias nativas con el mismo Node que usará el servicio.
|
||||||
|
PATH="$(dirname "$BUNDLED_NODE"):$PATH" npm rebuild node-hid --no-audit >>"$NODE_HID_LOG" 2>&1
|
||||||
|
"$BUNDLED_NODE" -e 'require("node-hid")'
|
||||||
log_ok " --> OK."
|
log_ok " --> OK."
|
||||||
|
|
||||||
# =======================
|
# =======================
|
||||||
@ -197,7 +217,7 @@ log_ok " --> OK."
|
|||||||
|
|
||||||
log_info "4) Aplicando permisos necesarios."
|
log_info "4) Aplicando permisos necesarios."
|
||||||
sudo chmod +x "$DEB_DIR/usr/share/emalibre/emalibre"
|
sudo chmod +x "$DEB_DIR/usr/share/emalibre/emalibre"
|
||||||
sudo chmod 0755 "$DEB_DIR/DEBIAN" "$DEB_DIR/DEBIAN/postrm" "$DEB_DIR/DEBIAN/postinst" "$DEB_DIR/DEBIAN/preinst"
|
sudo chmod 0755 "$DEB_DIR/DEBIAN" "$DEB_DIR/DEBIAN/postrm" "$DEB_DIR/DEBIAN/postinst" "$DEB_DIR/DEBIAN/preinst" "$DEB_DIR/DEBIAN/prerm"
|
||||||
sudo chown -R root:root "$DEB_DIR"
|
sudo chown -R root:root "$DEB_DIR"
|
||||||
log_ok " --> OK."
|
log_ok " --> OK."
|
||||||
|
|
||||||
@ -206,21 +226,36 @@ sudo ln -sf ../share/emalibre/emalibre "$DEB_DIR/usr/bin/emalibre"
|
|||||||
log_ok " --> OK."
|
log_ok " --> OK."
|
||||||
|
|
||||||
log_info "6) Eliminando node/web/express/forever/servicio para modo GUI y la interfaz para el modo web."
|
log_info "6) Eliminando node/web/express/forever/servicio para modo GUI y la interfaz para el modo web."
|
||||||
sudo mv "$DEB_DIR/etc/init.d" "$TMP_DIR" 2>/dev/null || true
|
# Restaurar las plantillas incluso si falla la construcción del paquete GUI.
|
||||||
sudo mv "$DEB_DIR/etc/emalibre_modo" "$TMP_DIR" 2>/dev/null || true
|
SERVICE_BACKUP=$(mktemp -d "$(pwd)/$TMP_DIR/service.XXXXXX")
|
||||||
sudo rm -rf "$DEB_DIR/usr/share/emalibre/node_modules/node" \
|
SERVICE_ETC="$(pwd)/$DEB_DIR/etc"
|
||||||
"$DEB_DIR/usr/share/emalibre/node_modules/express" \
|
restore_service() {
|
||||||
"$DEB_DIR/usr/share/emalibre/node_modules/forever" \
|
if [ -f "$SERVICE_BACKUP/emalibre" ]; then
|
||||||
"$DEB_DIR/usr/share/emalibre/node_modules/forever-agent" \
|
sudo mv "$SERVICE_BACKUP/emalibre" "$SERVICE_ETC/init.d/emalibre" || return
|
||||||
"$DEB_DIR/usr/share/emalibre/node_modules/forever-monitor" \
|
fi
|
||||||
"$DEB_DIR/usr/share/emalibre/gui_web"
|
if [ -f "$SERVICE_BACKUP/emalibre_modo" ]; then
|
||||||
|
sudo mv "$SERVICE_BACKUP/emalibre_modo" "$SERVICE_ETC/emalibre_modo" || return
|
||||||
|
fi
|
||||||
|
rmdir "$SERVICE_BACKUP"
|
||||||
|
}
|
||||||
|
trap restore_service EXIT
|
||||||
|
sudo mv "$SERVICE_ETC/init.d/emalibre" "$SERVICE_BACKUP/emalibre"
|
||||||
|
sudo mv "$SERVICE_ETC/emalibre_modo" "$SERVICE_BACKUP/emalibre_modo"
|
||||||
|
sudo rm -rf "$DEB_DIR/usr/share/emalibre/package.nw/node_modules/.bin/node" \
|
||||||
|
"$DEB_DIR/usr/share/emalibre/package.nw/node_modules/node-bin-setup" \
|
||||||
|
"$DEB_DIR/usr/share/emalibre/package.nw/node_modules/node" \
|
||||||
|
"$DEB_DIR/usr/share/emalibre/package.nw/node_modules/express" \
|
||||||
|
"$DEB_DIR/usr/share/emalibre/package.nw/node_modules/forever" \
|
||||||
|
"$DEB_DIR/usr/share/emalibre/package.nw/node_modules/forever-agent" \
|
||||||
|
"$DEB_DIR/usr/share/emalibre/package.nw/node_modules/forever-monitor" \
|
||||||
|
"$DEB_DIR/usr/share/emalibre/package.nw/gui_web"
|
||||||
log_ok " --> OK."
|
log_ok " --> OK."
|
||||||
|
|
||||||
log_info "7) Generando Paquete DEB para GUI 64 bits Linux."
|
log_info "7) Generando Paquete DEB para GUI 64 bits Linux."
|
||||||
#sudo dpkg -b Deb64 debs/"emalibre-gui-linux_$VERSION.deb"
|
#sudo dpkg -b Deb64 debs/"emalibre-gui-linux_$VERSION.deb"
|
||||||
sudo dpkg-deb -Zxz -b "$DEB_DIR" "$DEBS_OUT/emalibre-gui-linux_$VERSION.deb"
|
sudo dpkg-deb -Zxz -b "$DEB_DIR" "$DEBS_OUT/emalibre-gui-linux_$VERSION.deb"
|
||||||
sudo mv "$TMP_DIR/init.d" "$DEB_DIR/etc" 2>/dev/null || true
|
restore_service
|
||||||
sudo mv "$TMP_DIR/emalibre_modo" "$DEB_DIR/etc/emalibre_modo" 2>/dev/null || true
|
trap - EXIT
|
||||||
log_final " Finalizó con éxito, build/debs/emalibre-gui-linux_$VERSION.deb."
|
log_final " Finalizó con éxito, build/debs/emalibre-gui-linux_$VERSION.deb."
|
||||||
log_ok " --> OK."
|
log_ok " --> OK."
|
||||||
|
|
||||||
@ -261,7 +296,7 @@ sudo sed -i 's|/emalibre/package.nw/gui_common/|/emalibre/gui_common/|' "$DEB_DI
|
|||||||
log_ok " --> OK."
|
log_ok " --> OK."
|
||||||
|
|
||||||
log_info "4) Aplicando permisos necesarios."
|
log_info "4) Aplicando permisos necesarios."
|
||||||
sudo chmod 0755 "$DEB_DIR/DEBIAN" "$DEB_DIR/DEBIAN/postrm" "$DEB_DIR/DEBIAN/postinst" "$DEB_DIR/DEBIAN/preinst"
|
sudo chmod 0755 "$DEB_DIR/DEBIAN" "$DEB_DIR/DEBIAN/postrm" "$DEB_DIR/DEBIAN/postinst" "$DEB_DIR/DEBIAN/preinst" "$DEB_DIR/DEBIAN/prerm"
|
||||||
sudo chown -R root:root "$DEB_DIR"
|
sudo chown -R root:root "$DEB_DIR"
|
||||||
log_ok " --> OK."
|
log_ok " --> OK."
|
||||||
|
|
||||||
|
|||||||
@ -58,9 +58,11 @@
|
|||||||
"datatables.net": "1.13.11",
|
"datatables.net": "1.13.11",
|
||||||
"datatables.net-bs5": "1.13.11",
|
"datatables.net-bs5": "1.13.11",
|
||||||
"datatables.net-buttons": "2.4.3",
|
"datatables.net-buttons": "2.4.3",
|
||||||
"datatables.net-buttons-bs5": "2.4.3"
|
"datatables.net-buttons-bs5": "2.4.3",
|
||||||
|
"node": "22.23.3"
|
||||||
},
|
},
|
||||||
"allowScripts": {
|
"allowScripts": {
|
||||||
"node-hid@3.4.0": true
|
"node-hid@3.4.0": true,
|
||||||
|
"node@22.23.3": true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
206
test/init-service.test.py
Normal file
206
test/init-service.test.py
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
"""Exercise an isolated copy of the init script; never launch real daemons."""
|
||||||
|
import json
|
||||||
|
import os
|
||||||
|
from pathlib import Path
|
||||||
|
import shutil
|
||||||
|
import subprocess
|
||||||
|
import tempfile
|
||||||
|
import unittest
|
||||||
|
|
||||||
|
REPO = Path(__file__).resolve().parents[1]
|
||||||
|
NODE = shutil.which('node', path='/usr/bin:/bin')
|
||||||
|
|
||||||
|
@unittest.skipUnless(NODE, 'Node is required for the fake Forever module')
|
||||||
|
class InitServiceTest(unittest.TestCase):
|
||||||
|
def setUp(self):
|
||||||
|
self.temp = tempfile.TemporaryDirectory(prefix='emalibre-test-')
|
||||||
|
self.addCleanup(self.temp.cleanup)
|
||||||
|
self.root = Path(self.temp.name)
|
||||||
|
self.app = self.root / 'app'
|
||||||
|
self.module = self.app / 'node_modules/forever'
|
||||||
|
(self.module / 'bin').mkdir(parents=True)
|
||||||
|
(self.app / 'gui_web').mkdir()
|
||||||
|
(self.app / 'gui_web/express.js').touch()
|
||||||
|
(self.app / 'conf').mkdir()
|
||||||
|
self.config = self.app / 'conf/ConfiguracionGeneral.js'
|
||||||
|
self.config.write_text('module.exports = {ConfGeneral: {inicio_automatico: false}};')
|
||||||
|
self.state = self.root / 'state.json'
|
||||||
|
self.state.write_text('[]')
|
||||||
|
self.calls = self.root / 'calls.jsonl'
|
||||||
|
self.pid = self.root / 'emalibre.pid'
|
||||||
|
self.mode = self.root / 'mode'
|
||||||
|
self.mode.write_text('web\n')
|
||||||
|
self.module.joinpath('index.js').write_text('''
|
||||||
|
const fs = require('fs');
|
||||||
|
exports.stop = uid => {
|
||||||
|
const emitter = new (require('events').EventEmitter)();
|
||||||
|
process.nextTick(() => {
|
||||||
|
if (process.env.COMMAND_FAIL === 'stop') return emitter.emit('error', Error('stop failed'));
|
||||||
|
const state = JSON.parse(fs.readFileSync(process.env.TEST_STATE));
|
||||||
|
fs.writeFileSync(process.env.TEST_STATE, JSON.stringify(state.filter(p => p.uid !== uid)));
|
||||||
|
emitter.emit('stop');
|
||||||
|
});
|
||||||
|
return emitter;
|
||||||
|
};
|
||||||
|
exports.list = (_, cb) => cb(process.env.LIST_FAIL ? Error('query failed') : null,
|
||||||
|
JSON.parse(fs.readFileSync(process.env.TEST_STATE)));
|
||||||
|
''')
|
||||||
|
self.module.joinpath('bin/forever').write_text('''
|
||||||
|
const fs = require('fs');
|
||||||
|
const args = process.argv.slice(2);
|
||||||
|
fs.appendFileSync(process.env.TEST_CALLS, JSON.stringify(args) + '\\n');
|
||||||
|
if (process.env.COMMAND_FAIL === args[0]) process.exit(7);
|
||||||
|
let state = JSON.parse(fs.readFileSync(process.env.TEST_STATE));
|
||||||
|
if (args[0] === 'start') {
|
||||||
|
// Match Forever's tryStart: path.join(sourceDir, script), not path.resolve.
|
||||||
|
const script = require('path').join(args[args.indexOf('--sourceDir') + 1], args[args.length - 2]);
|
||||||
|
if (!fs.existsSync(script)) {
|
||||||
|
console.error('script ' + script + ' does not exist');
|
||||||
|
process.exit(255);
|
||||||
|
}
|
||||||
|
state.push({uid: 'EMA_Web'});
|
||||||
|
fs.writeFileSync(args[args.indexOf('--pidFile') + 1], '123456');
|
||||||
|
}
|
||||||
|
if (args[0] === 'stop') state = state.filter(p => p.uid !== args[1]);
|
||||||
|
fs.writeFileSync(process.env.TEST_STATE, JSON.stringify(state));
|
||||||
|
''')
|
||||||
|
wrapper = self.app / 'node_modules/node/bin/node'
|
||||||
|
wrapper.parent.mkdir(parents=True)
|
||||||
|
# Allow tests on older host Node; production still enforces Node >= 20.
|
||||||
|
wrapper.write_text('#!/bin/sh\nif [ "$1" = -e ]; then exit "${VERSION_FAIL:-0}"; fi\nexec ' + NODE + ' "$@"\n')
|
||||||
|
wrapper.chmod(0o755)
|
||||||
|
script = (REPO / 'build/Deb64/etc/init.d/emalibre').read_text()
|
||||||
|
for old, new in {
|
||||||
|
'/usr/share/emalibre': str(self.app),
|
||||||
|
'/run/emalibre.pid': str(self.pid),
|
||||||
|
'/var/log/emalibre': str(self.root / 'logs'),
|
||||||
|
'/etc/emalibre_modo': str(self.mode),
|
||||||
|
'/root/.forever': str(self.root / 'forever'),
|
||||||
|
'HOME=/root': 'HOME=' + str(self.root),
|
||||||
|
'/run/lock/emalibre.lock': str(self.root / 'lock'),
|
||||||
|
'/run/systemd/system': str(self.root / 'systemd'),
|
||||||
|
'$(id -u)': '${TEST_UID:-0}',
|
||||||
|
}.items():
|
||||||
|
script = script.replace(old, new)
|
||||||
|
# Both service managers are mocks; no system configuration is touched.
|
||||||
|
script = script.replace('set_boot() {', '''
|
||||||
|
systemctl() { echo "$*" >> "${TEST_BOOT}"; return "${BOOT_FAIL:-0}"; }
|
||||||
|
update-rc.d() { echo "$*" >> "${TEST_BOOT}"; return "${BOOT_FAIL:-0}"; }
|
||||||
|
set_boot() {''')
|
||||||
|
self.script = self.root / 'service'
|
||||||
|
self.script.write_text(script)
|
||||||
|
self.env = dict(os.environ, TEST_STATE=str(self.state), TEST_CALLS=str(self.calls),
|
||||||
|
TEST_BOOT=str(self.root / 'boot'))
|
||||||
|
|
||||||
|
def run_service(self, action, expected=0, **env):
|
||||||
|
result = subprocess.run(['bash', str(self.script), action], env=dict(self.env, **env),
|
||||||
|
capture_output=True, text=True, timeout=20)
|
||||||
|
self.assertEqual(result.returncode, expected, result.stdout + result.stderr)
|
||||||
|
return result
|
||||||
|
|
||||||
|
def commands(self):
|
||||||
|
return [json.loads(line) for line in self.calls.read_text().splitlines()] if self.calls.exists() else []
|
||||||
|
|
||||||
|
def test_start_and_idempotency(self):
|
||||||
|
self.run_service('start')
|
||||||
|
self.run_service('start')
|
||||||
|
self.assertEqual(len(self.commands()), 1)
|
||||||
|
self.assertEqual(self.commands()[0][-1], 'iniciar')
|
||||||
|
args = self.commands()[0]
|
||||||
|
self.assertEqual(args[args.index('-c') + 1], str(self.app / 'node_modules/node/bin/node'))
|
||||||
|
|
||||||
|
def test_stale_pid_does_not_block_start(self):
|
||||||
|
self.pid.write_text('123456')
|
||||||
|
self.run_service('start')
|
||||||
|
self.assertEqual(self.commands()[0][0], 'start')
|
||||||
|
|
||||||
|
def test_start_error_is_preserved(self):
|
||||||
|
self.run_service('start', 7, COMMAND_FAIL='start')
|
||||||
|
|
||||||
|
def test_stop_only_ema_and_without_pid(self):
|
||||||
|
self.state.write_text('[{"uid":"EMA_Web"},{"uid":"other"}]')
|
||||||
|
self.run_service('stop')
|
||||||
|
self.assertEqual(self.commands(), [['stop', 'EMA_Web']])
|
||||||
|
self.assertEqual(json.loads(self.state.read_text()), [{'uid': 'other'}])
|
||||||
|
|
||||||
|
def test_stop_idempotency_and_stale_pid(self):
|
||||||
|
self.pid.write_text('123456')
|
||||||
|
self.run_service('stop')
|
||||||
|
self.run_service('stop')
|
||||||
|
self.assertFalse(self.pid.exists())
|
||||||
|
self.assertEqual(self.commands(), [])
|
||||||
|
|
||||||
|
def test_stop_error_is_preserved(self):
|
||||||
|
self.state.write_text('[{"uid":"EMA_Web"}]')
|
||||||
|
self.run_service('stop', 7, COMMAND_FAIL='stop')
|
||||||
|
|
||||||
|
def test_restart_and_stop_failure(self):
|
||||||
|
self.state.write_text('[{"uid":"EMA_Web"}]')
|
||||||
|
self.run_service('restart', 7, COMMAND_FAIL='stop')
|
||||||
|
self.assertEqual(len(self.commands()), 1)
|
||||||
|
self.run_service('restart')
|
||||||
|
self.assertEqual([a[0] for a in self.commands()], ['stop', 'stop', 'start'])
|
||||||
|
|
||||||
|
def test_status(self):
|
||||||
|
self.run_service('status', 3)
|
||||||
|
self.state.write_text('[{"uid":"EMA_Web"}]')
|
||||||
|
self.run_service('status')
|
||||||
|
self.run_service('status', 4, LIST_FAIL='1')
|
||||||
|
|
||||||
|
def test_query_failure_prevents_start(self):
|
||||||
|
self.run_service('start', 4, LIST_FAIL='1')
|
||||||
|
self.assertEqual(self.commands(), [])
|
||||||
|
|
||||||
|
def test_mode_validation_and_default(self):
|
||||||
|
for value in ['', 'consola', 'web invalid']:
|
||||||
|
self.mode.write_text(value)
|
||||||
|
self.run_service('start', 2)
|
||||||
|
self.mode.unlink()
|
||||||
|
self.run_service('start')
|
||||||
|
self.assertEqual(self.mode.read_text(), 'web\n')
|
||||||
|
|
||||||
|
def test_missing_bundled_node_does_not_use_system_node(self):
|
||||||
|
(self.app / 'node_modules/node/bin/node').unlink()
|
||||||
|
self.run_service('start', 5)
|
||||||
|
self.assertEqual(self.commands(), [])
|
||||||
|
|
||||||
|
def test_missing_runtime_and_app(self):
|
||||||
|
self.run_service('start', 5, VERSION_FAIL='1')
|
||||||
|
(self.app / 'gui_web/express.js').unlink()
|
||||||
|
self.run_service('start', 5)
|
||||||
|
|
||||||
|
def test_usage_and_permissions(self):
|
||||||
|
self.run_service('invalid', 2)
|
||||||
|
self.run_service('start', 4, TEST_UID='1000')
|
||||||
|
|
||||||
|
def test_boot_independent_from_collection(self):
|
||||||
|
before = self.config.read_text()
|
||||||
|
self.run_service('set-inicio-enabled')
|
||||||
|
self.assertEqual((self.root / 'boot').read_text(), 'emalibre defaults\nemalibre enable\n')
|
||||||
|
(self.root / 'systemd').mkdir()
|
||||||
|
self.run_service('set-inicio-disable')
|
||||||
|
self.run_service('set-inicio-enabled', 9, BOOT_FAIL='9')
|
||||||
|
self.assertEqual(self.config.read_text(), before)
|
||||||
|
|
||||||
|
def test_migration_stops_only_ema(self):
|
||||||
|
source = (REPO / 'build/Deb64/DEBIAN/preinst').read_text()
|
||||||
|
js = source.split("<<'JS'\n", 1)[1].split('\nJS', 1)[0]
|
||||||
|
js = js.replace('/usr/share/emalibre', str(self.app))
|
||||||
|
for initial, expected, code, extra in [
|
||||||
|
([{'uid': 'EMA_Web'}, {'uid': 'other'}], [{'uid': 'other'}], 0, {}),
|
||||||
|
([{'uid': 'other'}], [{'uid': 'other'}], 0, {}),
|
||||||
|
([{'uid': 'EMA_Web'}], [{'uid': 'EMA_Web'}], 1, {'COMMAND_FAIL': 'stop'}),
|
||||||
|
]:
|
||||||
|
self.state.write_text(json.dumps(initial))
|
||||||
|
result = subprocess.run([NODE, '-'], input=js, text=True, capture_output=True,
|
||||||
|
env=dict(self.env, **extra), timeout=20)
|
||||||
|
self.assertEqual(result.returncode, code, result.stderr)
|
||||||
|
self.assertEqual(json.loads(self.state.read_text()), expected)
|
||||||
|
|
||||||
|
def test_view_does_not_create_mode(self):
|
||||||
|
self.mode.unlink()
|
||||||
|
self.run_service('view-conf', 1)
|
||||||
|
self.assertFalse(self.mode.exists())
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
unittest.main()
|
||||||
Loading…
Reference in New Issue
Block a user