Files
OpenViking/docker/openviking-entrypoint.sh
T
Zayn Jarvis d6a024efa5 feat(docker)!: drop legacy console (keep BFF + Caddy), ship web-studio in pip, fix favicons (#2160)
The OpenViking docker image still launched the legacy `openviking/console`
standalone service on port 8020. Now that web-studio is bundled into the OV
server itself at /studio (see #2156), that process is redundant and the
port is just a confusing artefact.

This change retires the old console (python package + 8020 + console-frontend
favicons) but **keeps the in-compose Caddy as a stable single-ingress on
port 1934**, just simplified to one upstream now that there's no 8020. The
server-side BFF at `openviking/server/routers/console.py` (under
`/api/v1/console/*`) is also kept — web-studio uses the same endpoints.

**The OAuth authorize page (`openviking/server/oauth/router.py`) is
deliberately untouched in this PR** — the console-link button and Quick
authorize same-origin panel will be re-pointed at web-studio in a focused
follow-up.

BREAKING CHANGES:
- Port 8020 is gone from the docker image and docker-compose.yml; Caddy at
  1934 now forwards everything to 1933 (web-studio lives at /studio there).
  Anything bookmarked at `http://host:8020/...` must migrate to
  `http://host:1933/studio/`.
- `python -m openviking.console.bootstrap` no longer exists; the python
  package `openviking.console` has been removed.

Pip packaging:
- web-studio dist is now shipped inside the wheel under
  `openviking/web_studio/dist/` (mirroring the old `openviking/console/static/`
  layout). The dockerfile copies `--from=web-studio-builder /web-studio/dist`
  into the source tree before `uv sync`, so the wheel produced by the
  default docker build always carries the SPA. Building the wheel without
  running `npm run build` first leaves the directory empty, which gracefully
  degrades /studio to a 404 without breaking server startup.
- Favicon assets (`favicon.ico` / `favicon-32.png` / `apple-touch-icon.png`,
  ~11 KB total) are duplicated into `openviking/server/static/` and shipped
  via package-data so `/favicon.*` and `/mcp/favicon.*` routes are always
  registered, regardless of whether the web-studio dist is bundled.
- `pyproject.toml` and `setup.py` `package-data` drop `console/static/**`
  and add `server/static/**` + `web_studio/dist/**`.
- New favicons (the 16/32/180 set in both `openviking/server/static/` and
  `web-studio/public/`) are downscaled from the canonical
  `web-studio/public/openviking-icon.png`, so the small-icon family matches
  the SPA's high-res rel="icon" target — the studio tab icon now stays
  consistent whether the browser uses the HTML link tag or falls back to
  auto-fetching `/favicon.ico`.

Server:
- `openviking/server/app.py` now reads `/studio` from
  `Path(__file__).parent.parent / 'web_studio' / 'dist'` by default;
  `OPENVIKING_WEB_STUDIO_DIR` still wins for dev mode pointing at a
  repo-local build. Favicon routes are unconditionally registered and
  load from `openviking/server/static/`.
- `openviking/observability/usage_audit/projection.py` drops the legacy
  `/console/*` skip prefix (the BFF prefix `/api/v1/console/*` remains).

Docker:
- `web-studio-builder` stage moved earlier (Stage 2) so its dist can flow
  into `py-builder` before `uv sync` runs.
- Runtime stage no longer separately copies the dist or sets
  `OPENVIKING_WEB_STUDIO_DIR`; the in-package path is the default.
- Entrypoint renamed `openviking-console-entrypoint.sh` -> `openviking-entrypoint.sh`
  and stripped of the `python -m openviking.console.bootstrap` launch.
- `EXPOSE 1933 8020` -> `EXPOSE 1933`.
- `docker-compose.yml` drops the openviking service's 8020 port mapping;
  the caddy service stays but no longer needs port 8020 exposed.
- `Caddyfile` simplified to a single `:1934 { reverse_proxy openviking:1933 }`
  — the legacy `/console/*` route to :8020 is gone.

Docs:
- en/zh quickstart updated to drop the 8020 mapping and explain that the
  API server now also serves `/studio`.
- Other guides (`12-public-access.md`, `11-oauth.md`, `05-observability.md`,
  `04-setup-for-agent.md`, `03-deployment.md`) are intentionally left for a
  focused follow-up PR alongside the OAuth quick-authorize reintroduction.

Tests:
- Deleted `tests/misc/test_console_{proxy,static_assets}.py` (covered the
  removed console package). `tests/observability/test_console_router.py`
  stays — it covers the BFF, which remains.
2026-05-21 16:41:29 +08:00

133 lines
3.6 KiB
Bash

#!/bin/sh
set -eu
SERVER_URL="http://127.0.0.1:1933"
SERVER_HEALTH_URL="${SERVER_URL}/health"
WITH_BOT="${OPENVIKING_WITH_BOT:-1}"
HEALTH_MAX_ATTEMPTS="${OPENVIKING_HEALTH_MAX_ATTEMPTS:-120}"
CONFIG_FILE="${OPENVIKING_CONFIG_FILE:-/app/.openviking/ov.conf}"
PENDING_HEALTH_SCRIPT="/usr/local/bin/openviking-pending-health"
SERVER_PID=""
PENDING_PID=""
stop_pending_health() {
if [ -n "${PENDING_PID}" ] && kill -0 "${PENDING_PID}" 2>/dev/null; then
kill "${PENDING_PID}" 2>/dev/null || true
wait "${PENDING_PID}" 2>/dev/null || true
fi
PENDING_PID=""
}
ensure_config() {
if [ -f "${CONFIG_FILE}" ]; then
return
fi
mkdir -p "$(dirname "${CONFIG_FILE}")"
if [ -n "${OPENVIKING_CONF_CONTENT:-}" ]; then
printf '%s' "${OPENVIKING_CONF_CONTENT}" > "${CONFIG_FILE}"
echo "[openviking-entrypoint] wrote ${CONFIG_FILE} from OPENVIKING_CONF_CONTENT"
return
fi
cat >&2 <<EOF
[openviking-entrypoint] ${CONFIG_FILE} not found.
To start OpenViking, do one of:
- mount ~/.openviking on the host to /app/.openviking
- set OPENVIKING_CONF_CONTENT to the full ov.conf JSON
- docker exec into this container and run: openviking-server init
While waiting, every HTTP request to this container returns a 503 JSON
describing the problem and the fix above.
EOF
OPENVIKING_CONFIG_FILE="${CONFIG_FILE}" \
OPENVIKING_PENDING_PORT="1933" \
python "${PENDING_HEALTH_SCRIPT}" &
PENDING_PID=$!
trap 'stop_pending_health; exit 0' INT TERM
while [ ! -f "${CONFIG_FILE}" ]; do
if ! kill -0 "${PENDING_PID}" 2>/dev/null; then
echo "[openviking-entrypoint] pending health server exited unexpectedly" >&2
PENDING_PID=""
exit 1
fi
sleep 5
done
stop_pending_health
trap - INT TERM
echo "[openviking-entrypoint] detected ${CONFIG_FILE}, starting OpenViking"
}
normalize_with_bot() {
case "$1" in
1|true|TRUE|yes|YES|on|ON)
WITH_BOT="1"
;;
0|false|FALSE|no|NO|off|OFF)
WITH_BOT="0"
;;
*)
echo "[openviking-entrypoint] invalid OPENVIKING_WITH_BOT=${1}" >&2
exit 2
;;
esac
}
if [ "$#" -gt 0 ]; then
for arg in "$@"; do
case "${arg}" in
--with-bot)
WITH_BOT="1"
;;
--without-bot)
WITH_BOT="0"
;;
*)
exec "$@"
;;
esac
done
fi
normalize_with_bot "${WITH_BOT}"
ensure_config
forward_signal() {
if [ -n "${SERVER_PID}" ] && kill -0 "${SERVER_PID}" 2>/dev/null; then
kill "${SERVER_PID}" 2>/dev/null || true
fi
}
trap 'forward_signal' INT TERM
SERVER_HOST="${OPENVIKING_SERVER_HOST:-0.0.0.0}"
if [ "${WITH_BOT}" = "1" ]; then
openviking-server --host "${SERVER_HOST}" --with-bot &
else
openviking-server --host "${SERVER_HOST}" &
fi
SERVER_PID=$!
attempt=0
until curl -fsS "${SERVER_HEALTH_URL}" >/dev/null 2>&1; do
attempt=$((attempt + 1))
if ! kill -0 "${SERVER_PID}" 2>/dev/null; then
echo "[openviking-entrypoint] openviking-server exited before becoming healthy" >&2
wait "${SERVER_PID}" || true
exit 1
fi
if [ "${attempt}" -ge "${HEALTH_MAX_ATTEMPTS}" ]; then
echo "[openviking-entrypoint] timed out waiting for ${SERVER_HEALTH_URL}" >&2
forward_signal
wait "${SERVER_PID}" || true
exit 1
fi
sleep 1
done
echo "[openviking-entrypoint] openviking-server is healthy"
wait "${SERVER_PID}" || SERVER_STATUS=$?
exit "${SERVER_STATUS:-0}"