Préréglage carte par défaut et serve-webapp.sh compatible Traefik
This commit is contained in:
188
serve-webapp.sh
188
serve-webapp.sh
@ -1,35 +1,39 @@
|
||||
#!/bin/bash
|
||||
# Stack webapp LiDAR — gestion du conteneur carte interactive sur la machine
|
||||
# légère (Raspberry Pi). Cf. docs/DEPLOY_WEBAPP.md.
|
||||
# Stack webapp LiDAR — gestion de la stack compose sur la machine légère
|
||||
# (Raspberry Pi). Cf. docs/DEPLOY_WEBAPP.md.
|
||||
#
|
||||
# Pilote docker compose (jamais docker run direct, qui ignorerait labels et
|
||||
# volumes de l'override) :
|
||||
# - docker-compose.webapp.yml (image légère Dockerfile.webapp, port 8973) ;
|
||||
# - docker-compose.webapp.override.yml s'il existe (non versionné : labels
|
||||
# Traefik, volume réel, environnement local) — chargé automatiquement :
|
||||
# la route publique HTTPS et le cache de tuiles réels sont préservés.
|
||||
#
|
||||
# Configuration : variables dans webapp.env (modèle : webapp.env.example,
|
||||
# non versionné) ou exportées dans l'environnement :
|
||||
# WEBAPP_PORT port hôte (défaut 8973)
|
||||
# LIDAR_GENERATION_URL machine de traitement (ex. http://192.168.1.50:8973)
|
||||
# LIDAR_REMOTE_TOKEN jeton si la machine exige LIDAR_API_TOKEN
|
||||
# LIDAR_REGEN_CIDR réseau autorisé à lancer les générations
|
||||
# (défaut 192.168.1.0/24, vide = restriction levée)
|
||||
# non versionné) ou exportées — elles alimentent l'interpolation compose
|
||||
# (${LIDAR_WEBAPP_HOST} des labels Traefik, etc.) ; l'environnement du
|
||||
# CONTENEUR vit dans les fichiers compose / override.
|
||||
#
|
||||
# GPS sur téléphone (optionnel) : l'API Geolocation exige une connexion
|
||||
# sécurisée. ./make-tls-cert.sh crée un certificat auto-signé dans ./tls ;
|
||||
# dès qu'il est présent, ce script sert la carte en HTTPS (https://<hôte>:port)
|
||||
# et le bouton ⌖ « centrer sur la position GPS » fonctionne sur téléphone
|
||||
# (accepter l'avertissement « certificat non fiable » une fois).
|
||||
# HTTPS : terminé par Traefik (override). Sans Traefik, monter ./tls via un
|
||||
# override local avec LIDAR_SSL_CERTFILE / LIDAR_SSL_KEYFILE (cf.
|
||||
# make-tls-cert.sh) — ce script ne gère plus le certificat auto-signé.
|
||||
#
|
||||
# Usage :
|
||||
# ./serve-webapp.sh [start] démarrer (arrière-plan, redémarrage auto)
|
||||
# ./serve-webapp.sh stop arrêter et supprimer le conteneur
|
||||
# ./serve-webapp.sh restart redémarrer (relit webapp.env)
|
||||
# ./serve-webapp.sh [start] démarrer (build + arrière-plan, redémarrage auto)
|
||||
# ./serve-webapp.sh stop arrêter et supprimer la stack (cache conservé)
|
||||
# ./serve-webapp.sh restart reconstruire l'image et recréer le conteneur
|
||||
# ./serve-webapp.sh status état du conteneur et de la dernière sync
|
||||
# ./serve-webapp.sh sync forcer un rebuild + régénération des vignettes
|
||||
# ./serve-webapp.sh logs suivre les logs du conteneur
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
||||
IMAGE="lidar-webapp"
|
||||
CONTAINER="lidar-webapp"
|
||||
COMPOSE_BASE="docker-compose.webapp.yml"
|
||||
COMPOSE_OVERRIDE="docker-compose.webapp.override.yml"
|
||||
|
||||
# Configuration locale (non versionnée) : webapp.env surcharge l'environnement
|
||||
# (sert à l'interpolation ${...} des fichiers compose).
|
||||
if [ -f "${SCRIPT_DIR}/webapp.env" ]; then
|
||||
set -a
|
||||
# shellcheck disable=SC1091
|
||||
@ -38,151 +42,109 @@ if [ -f "${SCRIPT_DIR}/webapp.env" ]; then
|
||||
fi
|
||||
WEBAPP_PORT="${WEBAPP_PORT:-8973}"
|
||||
|
||||
# HTTPS (requis pour la géolocalisation GPS depuis un téléphone) : l'API
|
||||
# Geolocation n'existe qu'en contexte sécurisé. Si le certificat auto-signé
|
||||
# ./tls (cf. ./make-tls-cert.sh) est présent, la carte est servie en
|
||||
# https://<hôte>:PORT ; le téléphone accepte l'avertissement « certificat non
|
||||
# fiable » une fois. Sans certificat : HTTP (le bouton GPS est indisponible).
|
||||
TLS_DIR="${SCRIPT_DIR}/tls"
|
||||
if [ -f "${TLS_DIR}/webapp.crt" ] && [ -f "${TLS_DIR}/webapp.key" ]; then
|
||||
SCHEME=https
|
||||
KFLAG=" -k" # -k : les sondes locales tolèrent le certificat auto-signé
|
||||
else
|
||||
SCHEME=http
|
||||
KFLAG=""
|
||||
COMPOSE_FILES=(-f "${SCRIPT_DIR}/${COMPOSE_BASE}")
|
||||
if [ -f "${SCRIPT_DIR}/${COMPOSE_OVERRIDE}" ]; then
|
||||
COMPOSE_FILES+=(-f "${SCRIPT_DIR}/${COMPOSE_OVERRIDE}")
|
||||
fi
|
||||
BASE_URL="${SCHEME}://127.0.0.1:${WEBAPP_PORT}"
|
||||
|
||||
CMD="${1:-start}"
|
||||
compose() {
|
||||
docker compose "${COMPOSE_FILES[@]}" "$@"
|
||||
}
|
||||
|
||||
build_image() {
|
||||
echo "Build de l'image webapp (cache Docker)..."
|
||||
if ! docker build -f "${SCRIPT_DIR}/Dockerfile.webapp" -t "$IMAGE" "$SCRIPT_DIR" > /tmp/lidar_webapp_build.log 2>&1; then
|
||||
cat /tmp/lidar_webapp_build.log >&2
|
||||
echo "Échec du build (journal : /tmp/lidar_webapp_build.log)" >&2
|
||||
exit 1
|
||||
fi
|
||||
# Port hôte réellement publié par le conteneur (mapping compose) ; repli sur
|
||||
# WEBAPP_PORT tant que le conteneur est arrêté.
|
||||
published_port() {
|
||||
local p
|
||||
p="$(docker port "$CONTAINER" 8973/tcp 2>/dev/null | head -1 | sed 's/.*://')"
|
||||
echo "${p:-$WEBAPP_PORT}"
|
||||
}
|
||||
|
||||
lan_ip() {
|
||||
hostname -I 2> /dev/null | awk '{print $1}'
|
||||
}
|
||||
|
||||
cmd_start() {
|
||||
mkdir -p "${SCRIPT_DIR}/output"
|
||||
if curl -fsS${KFLAG} "${BASE_URL}/api/status" > /dev/null 2>&1; then
|
||||
echo "Le port ${WEBAPP_PORT} répond déjà (webapp déjà lancée ?)." >&2
|
||||
echo "Arrêter l'existant, ou relancer avec un autre port : WEBAPP_PORT=9000 $0" >&2
|
||||
exit 1
|
||||
fi
|
||||
if ! docker image inspect "$IMAGE" > /dev/null 2>&1; then
|
||||
build_image
|
||||
fi
|
||||
ENV_ARGS=()
|
||||
if [ -n "${LIDAR_GENERATION_URL:-}" ]; then
|
||||
ENV_ARGS+=(-e LIDAR_GENERATION_URL="$LIDAR_GENERATION_URL")
|
||||
fi
|
||||
if [ -n "${LIDAR_REMOTE_TOKEN:-}" ]; then
|
||||
ENV_ARGS+=(-e LIDAR_REMOTE_TOKEN="$LIDAR_REMOTE_TOKEN")
|
||||
fi
|
||||
# Définie même vide (= restriction levée) ; absente = défaut webapp.py
|
||||
if [ -n "${LIDAR_REGEN_CIDR+x}" ]; then
|
||||
ENV_ARGS+=(-e LIDAR_REGEN_CIDR="${LIDAR_REGEN_CIDR:-}")
|
||||
fi
|
||||
# Certificat auto-signé (HTTPS → GPS téléphone) : monté en lecture seule
|
||||
# et activé via LIDAR_SSL_CERTFILE / LIDAR_SSL_KEYFILE (cf. make-tls-cert.sh).
|
||||
TLS_ARGS=()
|
||||
if [ "$SCHEME" = "https" ]; then
|
||||
TLS_ARGS+=(-v "${TLS_DIR}:/app/tls:ro")
|
||||
TLS_ARGS+=(-e LIDAR_SSL_CERTFILE=/app/tls/webapp.crt)
|
||||
TLS_ARGS+=(-e LIDAR_SSL_KEYFILE=/app/tls/webapp.key)
|
||||
fi
|
||||
# Clé SSH du hôte (déploiement, git pull distant) : montée en lecture seule
|
||||
# si présente. LIDAR_MOUNT_SSH=0 pour ne PAS l'exposer au conteneur
|
||||
# (durcissement : la webapp sert des requêtes réseau, inutile d'y donner
|
||||
# une clé privée si le git pull distant n'est pas utilisé).
|
||||
SSH_ARGS=()
|
||||
if [ "${LIDAR_MOUNT_SSH:-1}" = "1" ] && [ -d "${HOME}/.ssh" ]; then
|
||||
SSH_ARGS+=(-v "${HOME}/.ssh:/home/lidar/.ssh:ro")
|
||||
fi
|
||||
docker rm -f "$CONTAINER" > /dev/null 2>&1 || true
|
||||
docker run -d --init \
|
||||
--name "$CONTAINER" \
|
||||
--restart unless-stopped \
|
||||
--user 1000:1000 \
|
||||
-p "${WEBAPP_PORT}:8973" \
|
||||
-v "${SCRIPT_DIR}/output:/data/output" \
|
||||
"${TLS_ARGS[@]}" \
|
||||
"${SSH_ARGS[@]}" \
|
||||
-e LIDAR_OUTPUT_DIR=/data/output \
|
||||
"${ENV_ARGS[@]}" \
|
||||
"$IMAGE" > /dev/null
|
||||
echo -n "Attente du serveur sur le port ${WEBAPP_PORT}..."
|
||||
UP=0
|
||||
for _ in $(seq 1 30); do
|
||||
if curl -fsS${KFLAG} "${BASE_URL}/api/status" > /dev/null 2>&1; then
|
||||
UP=1
|
||||
wait_up() {
|
||||
echo -n "Attente du serveur sur le port $1..."
|
||||
local up=0 i
|
||||
for i in $(seq 1 30); do
|
||||
if curl -fsS "http://127.0.0.1:$1/api/status" > /dev/null 2>&1; then
|
||||
up=1
|
||||
break
|
||||
fi
|
||||
sleep 1
|
||||
done
|
||||
if [ "$UP" != "1" ]; then
|
||||
if [ "$up" != "1" ]; then
|
||||
echo " KO (voir ./serve-webapp.sh logs)" >&2
|
||||
exit 1
|
||||
fi
|
||||
echo " OK"
|
||||
}
|
||||
|
||||
cmd_start() {
|
||||
compose up -d --build
|
||||
wait_up "$(published_port)"
|
||||
local port
|
||||
port="$(published_port)"
|
||||
echo "============================================"
|
||||
echo " Carte LiDAR — webapp (${CONTAINER})"
|
||||
echo "============================================"
|
||||
echo " URL : ${BASE_URL}/"
|
||||
echo " URL : http://127.0.0.1:${port}/"
|
||||
if [ -n "$(lan_ip)" ]; then
|
||||
echo " URL (LAN) : ${SCHEME}://$(lan_ip):${WEBAPP_PORT}/"
|
||||
echo " URL (LAN) : http://$(lan_ip):${port}/"
|
||||
fi
|
||||
if [ "$SCHEME" = "https" ]; then
|
||||
echo " HTTPS (GPS tél.) : actif — sur le téléphone, acceptez l'avertissement « certificat non fiable »"
|
||||
if [ -f "${SCRIPT_DIR}/${COMPOSE_OVERRIDE}" ]; then
|
||||
echo " Override compose : ${COMPOSE_OVERRIDE} chargé (Traefik/volume local)"
|
||||
else
|
||||
echo " Override compose : absent (HTTP direct, sans Traefik)"
|
||||
fi
|
||||
echo " Génération distante: ${LIDAR_GENERATION_URL:-non configurée}"
|
||||
echo " Cache local tuiles : à la demande (LIDAR_GENERATION_URL)"
|
||||
echo " Génération distante: ${LIDAR_GENERATION_URL:-non configurée (override / webapp.env)}"
|
||||
echo "============================================"
|
||||
}
|
||||
|
||||
cmd_stop() {
|
||||
docker rm -f "$CONTAINER" > /dev/null 2>&1 || true
|
||||
echo "Conteneur ${CONTAINER} arrêté."
|
||||
compose down
|
||||
echo "Stack webapp arrêtée (conteneur ${CONTAINER} supprimé, cache conservé)."
|
||||
}
|
||||
|
||||
cmd_restart() {
|
||||
compose up -d --build --force-recreate
|
||||
wait_up "$(published_port)"
|
||||
echo "Stack webapp recréée (image reconstruite, relit webapp.env)."
|
||||
}
|
||||
|
||||
cmd_status() {
|
||||
if docker ps --format '{{.Names}}' 2> /dev/null | grep -qx "$CONTAINER"; then
|
||||
echo "Conteneur : ${CONTAINER} en cours d'exécution ($(docker ps --filter name="^${CONTAINER}$" --format '{{.Status}}'))"
|
||||
else
|
||||
echo "Conteneur : ${CONTAINER} arrêté"
|
||||
fi
|
||||
if curl -fsS${KFLAG} "${BASE_URL}/api/sync" 2> /dev/null; then
|
||||
compose ps
|
||||
local port
|
||||
port="$(published_port)"
|
||||
if curl -fsS "http://127.0.0.1:${port}/api/sync" 2> /dev/null; then
|
||||
echo ""
|
||||
else
|
||||
echo "Webapp : injoignable sur ${BASE_URL}"
|
||||
echo "Webapp : injoignable sur http://127.0.0.1:${port}" >&2
|
||||
fi
|
||||
}
|
||||
|
||||
cmd_sync() {
|
||||
CODE="$(curl -s${KFLAG} -o /dev/null -w '%{http_code}' -X POST "${BASE_URL}/api/sync" || true)"
|
||||
case "$CODE" in
|
||||
local port code
|
||||
port="$(published_port)"
|
||||
code="$(curl -s -o /dev/null -w '%{http_code}' -X POST "http://127.0.0.1:${port}/api/sync" || true)"
|
||||
case "$code" in
|
||||
200) echo "Sync lancée (suivi : ./serve-webapp.sh status, logs : ./serve-webapp.sh logs)" ;;
|
||||
409) echo "Une sync est déjà en cours (suivi : ./serve-webapp.sh status)" ;;
|
||||
*)
|
||||
echo "Échec : HTTP ${CODE:-pas de réponse} (webapp injoignable sur ${BASE_URL} ?)" >&2
|
||||
echo "Échec : HTTP ${code:-pas de réponse} (webapp injoignable sur http://127.0.0.1:${port} ?)" >&2
|
||||
exit 1
|
||||
;;
|
||||
esac
|
||||
}
|
||||
|
||||
CMD="${1:-start}"
|
||||
case "$CMD" in
|
||||
start) cmd_start ;;
|
||||
stop) cmd_stop ;;
|
||||
restart) cmd_stop; cmd_start ;;
|
||||
restart) cmd_restart ;;
|
||||
status) cmd_status ;;
|
||||
sync) cmd_sync ;;
|
||||
logs) exec docker logs -f "$CONTAINER" ;;
|
||||
logs) compose logs -f webapp ;;
|
||||
*)
|
||||
echo "Usage : $0 [start|stop|restart|status|sync|logs]" >&2
|
||||
exit 1
|
||||
|
||||
Reference in New Issue
Block a user