fix(furtka): move assets/ to repo top level so Caddy + systemd find it
Root cause of today's 403 on a fresh install: assets/ lived inside the Python package at furtka/assets/, so the resource-manager tarball extracted to /opt/furtka/versions/<ver>/furtka/assets/. But Caddyfile has `root * /opt/furtka/current/assets/www`, systemd units point at /opt/furtka/current/assets/bin/furtka-status, and the install-time `systemctl link /opt/furtka/current/assets/systemd/*.service` expected the top-level layout. All three found nothing: - Caddy → 403 Forbidden (empty/missing document root) - systemctl link → silent no-op, nothing ever linked into /etc/systemd/system/ - furtka-api.service + furtka-reconcile.service → "inactive" because they were never registered Nothing in the Python package ever imported furtka.assets — these are shell scripts, HTML/CSS, systemd units, and a Caddyfile, which is config data, not package data. Promoting assets/ to the repo root matches how it's referenced everywhere downstream and eliminates the path mismatch. Changes: - git mv furtka/assets assets - iso/build.sh: tarball-staging step now also `cp -a "$REPO_ROOT/assets"` so the tarball ships ./assets at its root, and the live-ISO copy reads from $REPO_ROOT/assets instead of $REPO_ROOT/furtka/assets. - scripts/build-release-tarball.sh: same for release tarballs. - webinstaller/app.py: _resolve_assets_dir's dev fallback walks one level up to REPO_ROOT/assets/. - tests/test_webinstaller_assets.py: ASSETS constant updated. Tests still green (150/150) because both paths were fs-level — no code imports changed. Next ISO build will land assets at the path everything downstream expects. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
661f51e91a
commit
c080764c7e
16 changed files with 14 additions and 8 deletions
|
|
@ -76,7 +76,7 @@ mkdir -p "$PROFILE_WORK/airootfs/opt/furtka"
|
|||
cp -a "$REPO_ROOT/webinstaller/." "$PROFILE_WORK/airootfs/opt/furtka/"
|
||||
# Ship the post-install asset tree (HTML, CSS, systemd units, scripts, …)
|
||||
# next to webinstaller/app.py so _resolve_assets_dir() finds it at runtime.
|
||||
cp -a "$REPO_ROOT/furtka/assets" "$PROFILE_WORK/airootfs/opt/furtka/assets"
|
||||
cp -a "$REPO_ROOT/assets" "$PROFILE_WORK/airootfs/opt/furtka/assets"
|
||||
rm -rf "$PROFILE_WORK/airootfs/opt/furtka/__pycache__"
|
||||
|
||||
# Pack the resource manager (furtka/ Python package + bundled apps/) as a
|
||||
|
|
@ -89,6 +89,9 @@ echo "==> Bundling resource manager payload"
|
|||
PAYLOAD_STAGE="$(mktemp -d)"
|
||||
cp -a "$REPO_ROOT/furtka" "$PAYLOAD_STAGE/"
|
||||
cp -a "$REPO_ROOT/apps" "$PAYLOAD_STAGE/"
|
||||
# assets/ ships at the tarball root (not inside the Python package) because
|
||||
# Caddy, systemd, and the updater all expect it at /opt/furtka/current/assets/.
|
||||
cp -a "$REPO_ROOT/assets" "$PAYLOAD_STAGE/"
|
||||
find "$PAYLOAD_STAGE" -type d -name __pycache__ -exec rm -rf {} +
|
||||
# VERSION at tarball root: the installer reads it to choose the versions/<ver>/
|
||||
# directory name and /opt/furtka/current/VERSION reports it at runtime.
|
||||
|
|
|
|||
|
|
@ -23,6 +23,9 @@ trap 'rm -rf "$STAGE"' EXIT
|
|||
|
||||
cp -a "$REPO_ROOT/furtka" "$STAGE/"
|
||||
cp -a "$REPO_ROOT/apps" "$STAGE/"
|
||||
# assets/ ships at the tarball root — Caddy + systemd + updater resolve
|
||||
# everything from /opt/furtka/current/assets/, never from inside the package.
|
||||
cp -a "$REPO_ROOT/assets" "$STAGE/"
|
||||
find "$STAGE" -type d -name __pycache__ -exec rm -rf {} +
|
||||
echo "$VERSION" > "$STAGE/VERSION"
|
||||
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ sys.path.insert(0, str(Path(__file__).resolve().parent.parent / "webinstaller"))
|
|||
import app # noqa: E402
|
||||
|
||||
REPO_ROOT = Path(__file__).resolve().parent.parent
|
||||
ASSETS = REPO_ROOT / "furtka" / "assets"
|
||||
ASSETS = REPO_ROOT / "assets"
|
||||
|
||||
|
||||
# (install target path, asset path under furtka/assets/) — only the files we
|
||||
|
|
|
|||
|
|
@ -148,7 +148,7 @@ def build_disk_config(boot_drive):
|
|||
# console shows a welcome banner pointing at the URL.
|
||||
#
|
||||
# Asset files (HTML, CSS, shell scripts, systemd units, Caddyfile) live in
|
||||
# furtka/assets/ in the repo — at ISO build time they end up on the live ISO
|
||||
# assets/ in the repo — at ISO build time they end up on the live ISO
|
||||
# as part of the webinstaller's source tree AND inside the resource-manager
|
||||
# payload tarball. The installer reads them from the live-ISO copy, base64-
|
||||
# encodes them, and hands them to archinstall so the chroot recreates each
|
||||
|
|
@ -157,7 +157,7 @@ def build_disk_config(boot_drive):
|
|||
# ---------------------------------------------------------------------------
|
||||
|
||||
# Tarball built by iso/build.sh containing the furtka/ Python package + the
|
||||
# bundled apps/ tree (plus furtka/assets/). The webinstaller reads it from the
|
||||
# bundled apps/ tree (plus assets/). The webinstaller reads it from the
|
||||
# live ISO at request-time and base64-encodes it into a custom_command for
|
||||
# archinstall.
|
||||
RESOURCE_MANAGER_PAYLOAD = Path("/opt/furtka-resource-manager.tar.gz")
|
||||
|
|
@ -165,9 +165,9 @@ RESOURCE_MANAGER_PAYLOAD = Path("/opt/furtka-resource-manager.tar.gz")
|
|||
|
||||
# Asset root. Two layouts we have to handle:
|
||||
# dev / tests — webinstaller/app.py sits at repo_root/webinstaller/ and
|
||||
# assets live at repo_root/furtka/assets/.
|
||||
# assets live at repo_root/assets/.
|
||||
# live ISO — iso/build.sh copies webinstaller/ to /opt/furtka/ AND
|
||||
# copies furtka/assets/ to /opt/furtka/assets/ right next to
|
||||
# copies assets/ to /opt/assets/ right next to
|
||||
# app.py, so the same "assets next to me" lookup works.
|
||||
# Probe the sibling path first (ISO case), fall back to the repo layout.
|
||||
def _resolve_assets_dir() -> Path:
|
||||
|
|
@ -175,7 +175,7 @@ def _resolve_assets_dir() -> Path:
|
|||
sibling = here / "assets"
|
||||
if sibling.is_dir():
|
||||
return sibling
|
||||
repo_copy = here.parent / "furtka" / "assets"
|
||||
repo_copy = here.parent / "assets"
|
||||
if repo_copy.is_dir():
|
||||
return repo_copy
|
||||
raise FileNotFoundError(
|
||||
|
|
@ -187,7 +187,7 @@ _ASSETS_DIR = _resolve_assets_dir()
|
|||
|
||||
|
||||
def _read_asset(relpath: str) -> str:
|
||||
"""Return the UTF-8 contents of an on-disk asset shipped under furtka/assets/.
|
||||
"""Return the UTF-8 contents of an on-disk asset shipped under assets/.
|
||||
|
||||
Raises FileNotFoundError if the asset is missing, which is loud by design:
|
||||
an install that tries to write an asset that isn't there is broken before
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue