Skip to content

feat(ingress): runtime per-workload CF ingress on /deploy#137

Merged
posix4e merged 1 commit into
mainfrom
feat/runtime-ingress
Apr 18, 2026
Merged

feat(ingress): runtime per-workload CF ingress on /deploy#137
posix4e merged 1 commit into
mainfrom
feat/runtime-ingress

Conversation

@posix4e
Copy link
Copy Markdown
Member

@posix4e posix4e commented Apr 18, 2026

Summary

Extends the boot-time `expose` feature from #134 to runtime. When a workload POSTed to dd-agent's `/deploy` declares `expose: {hostname_label, port}`, the agent now asks CP to route a public hostname to the workload's port — same shape as boot-time, just done dynamically.

Wire-level changes:

  • `src/cf.rs`: extract `apply_ingress()`; new public `update_ingress()` for runtime re-PUTs. Tunnel id + token stay stable across calls.
  • `src/cp.rs`: new `POST /ingress/replace` endpoint. PAT-authenticated, looks up the agent in the store by `agent_id`, re-PUTs the tunnel config, updates the store's `extras` field.
  • `src/collector.rs`: `Agent` struct gains `tunnel_id` + `extras` fields, preserved across `/health` scrapes so the collector doesn't clobber them.
  • `src/agent.rs`: stores `agent_id` from the register bootstrap, holds a live `Arc<RwLock<Vec<(String, u16)>>>` for the merged extras, hooks into `/deploy` to push updates. Soft-fails — workload stays running even if ingress push fails.

Depends on

What this unblocks

slopandmop's openclaw (and anything else POSTed at runtime) can now ask for `openclaw.` → `localhost:` and have it show up on the public internet within seconds. No more "v1 limitation: runtime exposure deferred" note.

Test plan

  • `cargo fmt && cargo check && cargo test` pass (10 lib tests)
  • Local: POST a spec with `"expose": {"hostname_label": "demo", "port": 9000}` to a running agent; curl `https://demo.`; expect 200
  • Log check: CP should log `cp: ingress/replace <agent_id> → ["demo.", ...]`; agent should log `agent: ingress/replace ok (N extras total)`
  • Re-POST the same app_name + hostname_label: no duplicate ingress rule (dedup by label)
  • Agent relaunch: only boot `extra_ingress` rules persist; runtime ones are intentionally dropped

🤖 Generated with Claude Code

@github-actions
Copy link
Copy Markdown

DD preview ready

URL: https://pr-137.devopsdefender.com

Browser login: paste gh auth token output at https://pr-137.devopsdefender.com/auth/pat

CLI / curl: curl -H "Authorization: Bearer $(gh auth token)" https://pr-137.devopsdefender.com/

Register endpoint for a local agent: wss://pr-137.devopsdefender.com/register

@posix4e posix4e force-pushed the feat/runtime-ingress branch from 65acc8a to f2f1825 Compare April 18, 2026 21:51
PR #134 wired `expose` at boot time — the ingress rules baked into the
agent VM's config.iso got published when CP first created the tunnel.
This extends that to the runtime path: when a workload POSTed to
dd-agent's /deploy declares `expose: {hostname_label, port}`, the agent
now calls the CP's new /ingress/replace endpoint with the merged
(boot + runtime) extras list, and CP re-PUTs the tunnel config +
upserts a CNAME for the new hostname.

Wire-level summary:

- cf.rs — extract `apply_ingress()` used by both `create()` (at
  register) and a new public `update_ingress()` (at runtime). The
  existing tunnel id + token stay stable.
- cp.rs — new endpoint POST /ingress/replace. PAT-authenticated,
  looks up the agent in the store by agent_id, re-PUTs the tunnel
  config, updates the store's `extras` field for the agent.
- collector::Agent — gains `tunnel_id` + `extras` fields, preserved
  across /health scrapes so the collector doesn't clobber them.
- agent.rs — stores `agent_id` from the register bootstrap, holds
  a live `Arc<RwLock<Vec<(String, u16)>>>` for the merged extras,
  hooks into /deploy to push updates. Soft-fails — workload stays
  running even if the ingress update fails; only public reachability
  is affected.

Opens the runtime path slopandmop needs: POST openclaw to an agent,
the agent asks CP to route `openclaw.<agent-host>` → localhost:port,
CF picks up the ingress config within seconds, browser hits the URL.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@posix4e posix4e force-pushed the feat/runtime-ingress branch from f2f1825 to 2377bd9 Compare April 18, 2026 21:51
@posix4e posix4e merged commit 37aeea6 into main Apr 18, 2026
4 checks passed
@posix4e posix4e deleted the feat/runtime-ingress branch April 18, 2026 21:56
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.

1 participant