Merge claude/1

This commit is contained in:
librelad 2026-05-24 16:53:37 +01:00
commit bace502044
10 changed files with 34 additions and 25 deletions

View File

@ -1191,6 +1191,12 @@ completeInitMessage()
fi fi
} }
# Only run the installer entrypoint (root check + init flow) when init.sh is
# EXECUTED directly. When it's SOURCED — start.sh loads init.sh for its function
# defs at runtime, and under Model A start.sh runs as the manager, not root — the
# defs above are all that's wanted and this root check must NOT fire.
[[ "${BASH_SOURCE[0]}" != "${0}" ]] && return 0 2>/dev/null
if [[ $EUID -ne 0 ]]; then if [[ $EUID -ne 0 ]]; then
echo "This script must be run as root." echo "This script must be run as root."
exit 1 exit 1

View File

@ -24,17 +24,17 @@ appStatus()
isHeader "App Status: $app_name" isHeader "App Status: $app_name"
# Check if container is running # Check if container is running
if docker ps --format '{{.Names}}' | grep -q "^${app_name}$"; then if runFileOp docker ps --format '{{.Names}}' | grep -q "^${app_name}$"; then
isSuccessful "Container: RUNNING" isSuccessful "Container: RUNNING"
else else
isNotice "Container: STOPPED" isNotice "Container: STOPPED"
fi fi
# Show basic container info if running # Show basic container info if running
if docker ps --format '{{.Names}}' | grep -q "^${app_name}$"; then if runFileOp docker ps --format '{{.Names}}' | grep -q "^${app_name}$"; then
echo "" echo ""
echo "Container Information:" echo "Container Information:"
docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep "$app_name" || echo "No port information available" runFileOp docker ps --format "table {{.Names}}\t{{.Status}}\t{{.Ports}}" | grep "$app_name" || echo "No port information available"
fi fi
echo "" echo ""

View File

@ -148,9 +148,9 @@ _backupDbWaitReady()
good=0 good=0
case "$kind" in case "$kind" in
postgres) postgres)
docker exec "$container" sh -c 'export PGPASSWORD="${POSTGRES_PASSWORD:-}"; psql -U "${POSTGRES_USER:-postgres}" -d "${POSTGRES_DB:-${POSTGRES_USER:-postgres}}" -tAc "SELECT 1"' >/dev/null 2>&1 && good=1 ;; runFileOp docker exec "$container" sh -c 'export PGPASSWORD="${POSTGRES_PASSWORD:-}"; psql -U "${POSTGRES_USER:-postgres}" -d "${POSTGRES_DB:-${POSTGRES_USER:-postgres}}" -tAc "SELECT 1"' >/dev/null 2>&1 && good=1 ;;
*) *)
docker exec "$container" sh -c 'RP="${MARIADB_ROOT_PASSWORD:-$MYSQL_ROOT_PASSWORD}"; mariadb -uroot -p"$RP" -N -e "SELECT 1" 2>/dev/null || mysql -uroot -p"$RP" -N -e "SELECT 1"' >/dev/null 2>&1 && good=1 ;; runFileOp docker exec "$container" sh -c 'RP="${MARIADB_ROOT_PASSWORD:-$MYSQL_ROOT_PASSWORD}"; mariadb -uroot -p"$RP" -N -e "SELECT 1" 2>/dev/null || mysql -uroot -p"$RP" -N -e "SELECT 1"' >/dev/null 2>&1 && good=1 ;;
esac esac
if [[ $good -eq 1 ]]; then if [[ $good -eq 1 ]]; then
ok=$((ok + 1)) ok=$((ok + 1))
@ -199,7 +199,7 @@ backupDbDump()
case "$kind" in case "$kind" in
postgres) postgres)
isNotice "Dumping postgres ($container) — live, consistent" isNotice "Dumping postgres ($container) — live, consistent"
if docker exec "$container" sh -c \ if runFileOp docker exec "$container" sh -c \
'export PGPASSWORD="${POSTGRES_PASSWORD:-}"; pg_dump --clean --if-exists -U "${POSTGRES_USER:-postgres}" -d "${POSTGRES_DB:-${POSTGRES_USER:-postgres}}"' \ 'export PGPASSWORD="${POSTGRES_PASSWORD:-}"; pg_dump --clean --if-exists -U "${POSTGRES_USER:-postgres}" -d "${POSTGRES_DB:-${POSTGRES_USER:-postgres}}"' \
2>/dev/null | gzip | runFileWrite "$dump"; then 2>/dev/null | gzip | runFileWrite "$dump"; then
isSuccessful "postgres dump written ($container)" isSuccessful "postgres dump written ($container)"
@ -209,7 +209,7 @@ backupDbDump()
;; ;;
mysql|mariadb) mysql|mariadb)
isNotice "Dumping $kind ($container) — live, consistent" isNotice "Dumping $kind ($container) — live, consistent"
if docker exec "$container" sh -c \ if runFileOp docker exec "$container" sh -c \
'RP="${MARIADB_ROOT_PASSWORD:-$MYSQL_ROOT_PASSWORD}"; DB="${MARIADB_DATABASE:-$MYSQL_DATABASE}"; (mariadb-dump -uroot -p"$RP" --single-transaction --routines --triggers --databases "$DB" 2>/dev/null || mysqldump -uroot -p"$RP" --single-transaction --routines --triggers --databases "$DB")' \ 'RP="${MARIADB_ROOT_PASSWORD:-$MYSQL_ROOT_PASSWORD}"; DB="${MARIADB_DATABASE:-$MYSQL_DATABASE}"; (mariadb-dump -uroot -p"$RP" --single-transaction --routines --triggers --databases "$DB" 2>/dev/null || mysqldump -uroot -p"$RP" --single-transaction --routines --triggers --databases "$DB")' \
2>/dev/null | gzip | runFileWrite "$dump"; then 2>/dev/null | gzip | runFileWrite "$dump"; then
isSuccessful "$kind dump written ($container)" isSuccessful "$kind dump written ($container)"

View File

@ -18,8 +18,8 @@ checkDockerNetworkRequirement()
((preinstallneeded++)) ((preinstallneeded++))
fi fi
elif [[ $CFG_DOCKER_INSTALL_TYPE == "rooted" ]]; then elif [[ $CFG_DOCKER_INSTALL_TYPE == "rooted" ]]; then
if docker network inspect $CFG_NETWORK_NAME > /dev/null 2>&1; then if runFileOp docker network inspect $CFG_NETWORK_NAME > /dev/null 2>&1; then
local current_subnet=$(docker network inspect $CFG_NETWORK_NAME --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}' 2>/dev/null) local current_subnet=$(runFileOp docker network inspect $CFG_NETWORK_NAME --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}' 2>/dev/null)
if [[ "$current_subnet" == "$CFG_NETWORK_SUBNET" ]]; then if [[ "$current_subnet" == "$CFG_NETWORK_SUBNET" ]]; then
isSuccessful "Docker Network $CFG_NETWORK_NAME exists with matching subnet" isSuccessful "Docker Network $CFG_NETWORK_NAME exists with matching subnet"

View File

@ -1,14 +1,17 @@
#!/bin/bash #!/bin/bash
checkRootRequirement() checkRootRequirement()
{ {
if [[ $CFG_REQUIREMENT_ROOT == "true" ]]; then if [[ $CFG_REQUIREMENT_ROOT == "true" ]]; then
# Check if script is run as root # Model A least-privilege: the app runs AS the manager user and escalates
if [[ $EUID -ne 0 ]]; then # only specific commands via runSystem, so accept the manager as well as
echo "This script must be run as root." # root — not root-only. (init.sh keeps its own install-time root check.)
exit 1 local mgr="${sudo_user_name:-libreportal}"
if [[ $EUID -eq 0 || "$(id -un)" == "$mgr" ]]; then
isSuccessful "Running as $(id -un)."
else else
isSuccessful "Script ran under root user." echo "This script must be run as root or the manager user ($mgr)."
exit 1
fi fi
fi fi
} }

View File

@ -204,7 +204,7 @@ validateDockerService() {
} }
validateContainerHealth() { validateContainerHealth() {
local containerInfo=$(docker ps -a --filter "name=libreportal-service" --format "{{.Status}}|{{.Names}}" 2>/dev/null) local containerInfo=$(runFileOp docker ps -a --filter "name=libreportal-service" --format "{{.Status}}|{{.Names}}" 2>/dev/null)
if [ -z "$containerInfo" ]; then if [ -z "$containerInfo" ]; then
healthLogError "LibrePortal WebUI container not found" healthLogError "LibrePortal WebUI container not found"
@ -214,7 +214,7 @@ validateContainerHealth() {
if echo "$status" | grep -q "Up"; then if echo "$status" | grep -q "Up"; then
# Check if container is responsive # Check if container is responsive
if docker exec libreportal-service pgrep -f "node.*webui" >/dev/null 2>&1; then if runFileOp docker exec libreportal-service pgrep -f "node.*webui" >/dev/null 2>&1; then
healthLogSuccess "Container is running and responsive" healthLogSuccess "Container is running and responsive"
else else
healthLogWarning "Container is running but WebUI process not found" healthLogWarning "Container is running but WebUI process not found"
@ -226,7 +226,7 @@ validateContainerHealth() {
validateWebUIReadiness() { validateWebUIReadiness() {
# Get the actual port mapping from the container # Get the actual port mapping from the container
local portMapping=$(docker port libreportal-service 2>/dev/null | head -1) local portMapping=$(runFileOp docker port libreportal-service 2>/dev/null | head -1)
if [ -z "$portMapping" ]; then if [ -z "$portMapping" ]; then
healthLogWarning "No port mapping found for libreportal-service container" healthLogWarning "No port mapping found for libreportal-service container"

View File

@ -4,6 +4,6 @@ dockerCheckAppHealthDetails()
{ {
local app_name="$1" local app_name="$1"
result=$(docker inspect --format "{{json .State.Health }}" $app_name | jq) result=$(runFileOp docker inspect --format "{{json .State.Health }}" $app_name | jq)
checkSuccess "Getting $app_name health details." checkSuccess "Getting $app_name health details."
} }

View File

@ -4,6 +4,6 @@ dockerCheckAppHealthStatus()
{ {
local app_name="$1" local app_name="$1"
result=$(docker inspect --format "{{json .State.Health.Status }}" $app_name) result=$(runFileOp docker inspect --format "{{json .State.Health.Status }}" $app_name)
checkSuccess "Getting $app_name health status." checkSuccess "Getting $app_name health status."
} }

View File

@ -7,11 +7,11 @@ dockerPruneAppNetworks()
if [ ! -z "$app_name" ]; then if [ ! -z "$app_name" ]; then
local networks_found=false local networks_found=false
# Prune all networks except those containing the specified app_name # Prune all networks except those containing the specified app_name
for network_id in $(docker network ls --quiet); do for network_id in $(runFileOp docker network ls --quiet); do
network_name=$(docker network inspect --format '{{.Name}}' "$network_id") network_name=$(runFileOp docker network inspect --format '{{.Name}}' "$network_id")
if [[ "$network_name" == *"$app_name"* ]]; then if [[ "$network_name" == *"$app_name"* ]]; then
local result=$(dockerCommandRun "docker network rm "$network_id"") local result=$(dockerCommandRun "docker network rm "$network_id"")
checkSuccess "Removing the unused docker network - $network_name" checkSuccess "Removing the unused runFileOp docker network - $network_name"
networks_found=true networks_found=true
fi fi
done done

View File

@ -14,7 +14,7 @@ ipIsAvailable()
local existing=$(sqlite3 "$docker_dir/$db_file" "SELECT resource_value FROM network_resources WHERE resource_type = 'ip' AND resource_value = '$test_ip' AND status = 'active';" 2>/dev/null) local existing=$(sqlite3 "$docker_dir/$db_file" "SELECT resource_value FROM network_resources WHERE resource_type = 'ip' AND resource_value = '$test_ip' AND status = 'active';" 2>/dev/null)
if [[ -n "$existing" ]]; then if [[ -n "$existing" ]]; then
ip_available="" ip_available=""
elif docker network inspect $CFG_NETWORK_NAME --format '{{range .Containers}}{{.IPv4Address}} {{end}}' 2>/dev/null | grep -q "$test_ip"; then elif runFileOp docker network inspect $CFG_NETWORK_NAME --format '{{range .Containers}}{{.IPv4Address}} {{end}}' 2>/dev/null | grep -q "$test_ip"; then
ip_available="" ip_available=""
else else
ip_available="$test_ip" ip_available="$test_ip"