#!/bin/bash # Which user does a config write drop to, for an app on a second disk? # # scripts/dev/lp-config-write-test # # `sed -i` writes its temporary file next to the target, so it needs write # permission on the DIRECTORY. App directories are owned by the container user, # so the manager cannot write in them and the write has to drop privilege. # # updateConfigOption chose that by comparing the path against $containers_dir — # the PRIMARY root only. An app installed on any other registered storage # location therefore took the manager branch and failed with # # sed: couldn't open temporary file /mnt/disk2/apps//sedXXXXXX: Permission denied # # which is the exact failure the comment above that code describes. Callers that # tolerate a failed write hid it: `app move` persists the new location with # `updateConfigOption ... || true`, so it reported a successful move while # leaving the config naming the old disk. REPO="$(cd "$(dirname "$0")/../.." && pwd)" BASE="$(mktemp -d "${TMPDIR:-/tmp}/lp-cfgwrite-test-XXXXXX")" trap 'rm -rf "$BASE"' EXIT fail=0 chk(){ if [[ "$2" == "$3" ]]; then echo " ok $1"; else echo " FAIL $1: got '$2' want '$3'"; fail=1; fi; } containers_dir="$BASE/primary/" mkdir -p "$BASE/primary/appA" "$BASE/disk2/appB" "$BASE/sys/configs" for f in "$BASE/primary/appA/appA.config" "$BASE/disk2/appB/appB.config" "$BASE/sys/configs/general"; do mkdir -p "$(dirname "$f")"; printf 'CFG_X=old # a comment\n' > "$f" done # The resolver knows every registered root; the primary-only comparison did not. pathIsContainerData(){ [[ "$1" == "$BASE/primary/"* || "$1" == "$BASE/disk2/"* ]] } source "$REPO/scripts/docker/command/run_privileged.sh" 2>/dev/null || true # Record which helper the write is routed through instead of actually escalating. CHOSE="" runFileOp(){ CHOSE="runFileOp"; shift 0; "$@"; } runInstallOp(){ CHOSE="runInstallOp"; shift 0; "$@"; } runAsManager(){ "$@"; } isError(){ :; }; isSuccessful(){ :; }; isNotice(){ :; }; isQuestion(){ :; } checkSuccess(){ :; } source "$REPO/scripts/config/core/config_update_option.sh" echo "--- an app on the PRIMARY root ---" CHOSE=""; updateConfigOption CFG_X newA "$BASE/primary/appA/appA.config" >/dev/null 2>&1 chk "drops to the container user" "$CHOSE" "runFileOp" chk "and the value landed" "$(grep -c 'newA' "$BASE/primary/appA/appA.config")" "1" echo "--- an app on a SECOND registered location (the case that failed) ---" CHOSE=""; updateConfigOption CFG_X newB "$BASE/disk2/appB/appB.config" >/dev/null 2>&1 chk "drops to the container user" "$CHOSE" "runFileOp" chk "and the value landed" "$(grep -c 'newB' "$BASE/disk2/appB/appB.config")" "1" echo "--- a manager-owned system config stays with the manager ---" CHOSE=""; updateConfigOption CFG_X newS "$BASE/sys/configs/general" >/dev/null 2>&1 chk "stays with the manager" "$CHOSE" "runInstallOp" echo "" if (( fail )); then echo "FAILED"; exit 1; fi echo "All config-write routing checks passed."