cli: graceful fallback when --write-env can't write the host-mounted .env
The CLI runs inside the gateway container as the non-root `gateway` user (uid 10001). The .env file is typically host-mounted at /app/.env, owned by the host user — so the container process can't write the .env.tmp file `update_env_file()` creates for the atomic rename. That surfaced as a raw PermissionError traceback from `docker exec neuronetz-gateway neuronetz-gateway remove-backend …`. Now both add-backend and remove-backend catch PermissionError / OSError on the write, print a tidy red message, and tell the user the two ways forward: re-run with `docker exec -u root …` (in-container root keeps the same FS, just bypasses ownership), or paste the printed OLLAMA_BACKENDS line manually. Exit 1 either way so scripts notice.
This commit is contained in:
@@ -448,6 +448,27 @@ def probe_ollama(
|
||||
typer.secho("upstream reachable and authenticated.", fg=typer.colors.GREEN, bold=True)
|
||||
|
||||
|
||||
def _emit_paste_fallback(path: Path, line: str, exc: BaseException) -> None:
|
||||
"""Print a clean fallback message when --write-env can't write the file.
|
||||
|
||||
The bootstrap CLI usually runs inside the gateway container (uid 10001),
|
||||
but the host-mounted .env is typically owned by the host user — so the
|
||||
in-container process can't write it. Instead of crashing with a traceback,
|
||||
print the line the user can paste, and tell them how to retry with the
|
||||
right privileges.
|
||||
"""
|
||||
typer.secho(f"✗ could not write {path}: {type(exc).__name__}", fg=typer.colors.RED)
|
||||
typer.echo(f" ({exc})")
|
||||
typer.echo("")
|
||||
typer.echo("Two ways forward:")
|
||||
typer.echo(" 1. Re-run the same command with `docker exec -u root …` so the in-container")
|
||||
typer.echo(" process can write to the host-mounted .env.")
|
||||
typer.echo(" 2. Paste this into your .env manually, then `docker compose up -d gateway`:")
|
||||
typer.echo("")
|
||||
typer.echo(f" OLLAMA_BACKENDS={line}")
|
||||
typer.echo("")
|
||||
|
||||
|
||||
@app.command("list-backends")
|
||||
def list_backends() -> None:
|
||||
"""Show the configured Ollama backends (tokens redacted).
|
||||
@@ -588,7 +609,11 @@ def add_backend(
|
||||
line = serialize(updated)
|
||||
if write_env is not None:
|
||||
path = Path(write_env)
|
||||
try:
|
||||
update_env_file(path, line)
|
||||
except (PermissionError, OSError) as exc:
|
||||
_emit_paste_fallback(path, line, exc)
|
||||
raise typer.Exit(code=1) from exc
|
||||
typer.echo(f"✓ updated {path}")
|
||||
typer.echo(" recreate the gateway: docker compose up -d gateway")
|
||||
else:
|
||||
@@ -643,7 +668,12 @@ def remove_backend(
|
||||
return
|
||||
|
||||
if write_env is not None:
|
||||
update_env_file(Path(write_env), line)
|
||||
path = Path(write_env)
|
||||
try:
|
||||
update_env_file(path, line)
|
||||
except (PermissionError, OSError) as exc:
|
||||
_emit_paste_fallback(path, line, exc)
|
||||
raise typer.Exit(code=1) from exc
|
||||
typer.echo(f"✓ updated {write_env}")
|
||||
typer.echo(" recreate the gateway: docker compose up -d gateway")
|
||||
else:
|
||||
|
||||
Reference in New Issue
Block a user