Skip to content

feat(infra): GET /v1/infra/mirror/health — the route the canvas mirror node already polls - #124

Merged
pparage merged 2 commits into
devfrom
feat/infra-mirror-health
Aug 6, 2026
Merged

feat(infra): GET /v1/infra/mirror/health — the route the canvas mirror node already polls#124
pparage merged 2 commits into
devfrom
feat/infra-mirror-health

Conversation

@pparage

@pparage pparage commented Aug 6, 2026

Copy link
Copy Markdown
Member

Salvaged from feat/local-apt-mirror (87de7eb), which has sat unmerged since 20 May. Checked while cleaning up stale branches: there is no v1 replacement — there is no replacement at all.

deployer-ui dev ships src/components/nodes/InfraNodeMirror.vue, which polls /v0/infra/mirror/health every 30 seconds. No such route exists on backend dev (app/routes/infra.py does not exist there, and nothing references APT_MIRROR_*), so the mirror node has always rendered offline — the same failure mode as the /v1/.../vms/{vmid}/config route the UI was calling in #98.

Changes from the original commit

  • Mounted under /v1, not /v0. This is new surface, and v0 is legacy and shrinking (Bundle rename alignment: dotted names, generic/ tier, proxmox decom #113 removed a large chunk of it today). deployer-ui 9ac8258 updates the fetch path in lockstep, so the two land together.
  • Project logger (app.core.logging.get_logger) instead of stdlib logging.
  • Tests — the original had none, and ruff + pytest now gate CI (chore(ci): add CI workflow and Dependabot hardening #92). Six cases: unconfigured, healthy, air-gapped backend label, degraded on non-200, and both transport failures. That last pair matters: the node polls on a timer, so a mirror that is down must report offline, not surface a 500.

Authorship of the original commit is preserved.

Also in here

.gitignore now excludes collections/ansible-galaxy install -p ./collections drops ~4200 vendored files into the worktree, and they nearly ended up committed.

443 passed, ruff clean, openapi.json regenerated.

Once this merges, feat/local-apt-mirror can be deleted; its only commit is superseded by this one.

pparage and others added 2 commits August 6, 2026 10:43
ansible-galaxy install -p ./collections drops ~4200 vendored files into
the worktree; they are a local install artifact, not source.
Salvaged from feat/local-apt-mirror (87de7eb, unmerged since May 20).
deployer-ui already ships InfraNodeMirror.vue, which polls this endpoint
every 30s — with no route on dev the node has always rendered offline.

Changes from the original commit:
- mounted under /v1 rather than /v0: this is new surface and v0 is
  legacy and shrinking. The UI fetch path is updated in lockstep.
- uses the project structlog logger instead of stdlib logging
- adds the tests the original lacked: unconfigured, healthy, air-gapped
  backend label, degraded, and both transport failures — a down mirror
  must report offline rather than 500, since the node polls on a timer
@pparage
pparage merged commit 92523d9 into dev Aug 6, 2026
3 checks passed
@pparage
pparage deleted the feat/infra-mirror-health branch August 6, 2026 08:49

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 49e5de512e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread app/routes/infra.py
Comment on lines +63 to +66
except httpx.ConnectError:
return JSONResponse({"status": "offline", "detail": "connection refused"}, status_code=503)
except httpx.TimeoutException:
return JSONResponse({"status": "offline", "detail": "timeout"}, status_code=503)

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Handle all HTTPX transport failures as offline

When the mirror accepts a connection but then resets it or sends an invalid/truncated response, HTTPX raises another RequestError subtype such as ReadError or RemoteProtocolError. Neither handler catches those failures, so this polling endpoint surfaces a 500 instead of the documented offline response; catch the broader transport/request exception family while preserving the timeout detail if needed.

Useful? React with 👍 / 👎.

Comment thread app/routes/infra.py
return JSONResponse(
{
"status": "healthy",
"backend": "aptly" if os.getenv("APT_MIRROR_AIRGAPPED") else "acng",

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Parse the air-gapped setting as a boolean

When deployment configuration explicitly supplies APT_MIRROR_AIRGAPPED=false or 0 rather than omitting it, os.getenv(...) returns a nonempty string and this reports the backend as aptly. Parse recognized true values, as the existing boolean settings do, so an explicitly false flag continues to identify the ACNG backend.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants