Commit Graph

35 Commits

Author SHA1 Message Date
unkin-agent 2feb365c31 Store a completed build on a context detached from the flight
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
2026-09-05 22:20:53 +10:00
unkin-agent be4dbb47a9 Cancel a shared flight when its last participant leaves
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
Reference-count flightCall so the fan-out context ends with the last
caller waiting on it, keeping cfg.Timeout as the upper bound. A leader
leaving with a follower still parked no longer disturbs the flight, and
a solo requester disconnecting releases the upstream sockets at once
instead of holding them for the whole timeout.

Return errFlightAbandoned from Do rather than inferring the abandon path
from the request context's sentinel, and read Age off the server's clock
so it matches the timestamp the cache stored.
2026-09-05 22:05:16 +10:00
unkin-agent 7fe58939dd Mark cached responses with X-Cache and Age
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
A stale fallback is byte-identical to a fresh response, so a client has
no way to tell it is holding data pdbmux served only because every
backend was down; the sole signal is a log line and a /healthz counter.

Set X-Cache to hit, miss or stale and Age to whole seconds since the
served copy was stored on every response from a cached path. Neither
header is emitted by OpenVoxDB, so nothing upstream is shadowed.
2026-09-05 21:29:34 +10:00
unkin-agent c77298584d Detach the shared fan-out from its leader's request context
A single flight is built by whichever request arrived first, but every
request on that key waits for it. Running the fan-out on the leader's
cancelable request context hands the leader's disconnect to followers
whose own connections are healthy: they get 502 all backends failed.
Waiters also parked on a WaitGroup, so a follower whose own client went
away stayed blocked until the leader finished.

Run the flight on a context detached from the leader's request and
bounded by the configured timeout, and pass that context into build so
the fan-out uses it. Give Do a context so a waiter can abandon a flight
it no longer needs; the leader ignores it and always runs fn to
completion, keeping the cache warm for the others. A caller that
abandons on its own cancellation writes no response.
2026-09-05 21:29:20 +10:00
unkin-agent c0aab83c20 Convert a single-flight panic into an error
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
- flightGroup.Do recovers a panicking fn so the leader and every waiter get a non-nil error instead of a zero-value success served as 200 []
- Note in the README that facts_cache_bytes budgets body bytes only
2026-09-05 21:03:23 +10:00
unkin-agent 1e2acc9c14 feat: cache merged /facts and /nodes in memory, stale on backend failure
A busy Puppetboard re-fans-out the same /facts query every few seconds, and a
502 is worse than 30-second-old facts when every PuppetDB is unreachable.

- Add a `Cache` interface (get reports fresh/stale/miss, put, stats) keyed on
  `<path>?<params>` with keys and repeated values sorted, plus a no-op default
  so uncached paths behave exactly as before.
- Route serveMerged/serveUnion/serveSummed through `serveCached`, so the
  reports cache drops in at `cacheFor` without touching a handler.
- Back /facts and /nodes with a byte-bounded LRU: `facts_ttl` (default 30s,
  clamped to a 30s cap) and `facts_cache_bytes` (default 64 MiB); expired
  entries are kept and served only when every backend fails.
- Single-flight identical keys so N concurrent requests cause one fan-out.
- Surface `cache` state and `serving_stale` in /healthz and the cache settings
  in `config show`.
2026-09-05 21:03:23 +10:00
benvin 394f7df3a7 Merge pull request 'Serve PuppetDB meta and metrics endpoints, sum node and resource counts' (#11) from benvin/meta-metrics-and-counts into main
Reviewed-on: #11
2026-09-05 20:56:06 +10:00
unkin-agent b6d59af7ef Serve PuppetDB meta and metrics endpoints, sum node and resource counts
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
## Why
Puppetboard 7.0.1 cannot run against pdbmux: it exits at import when
/pdb/meta/v1/version 404s, and its landing page, metrics and radiator views
404 on the Jolokia surface.

## How
- Serve /pdb/meta/v1/version, reporting the lowest version any backend runs,
  and /pdb/meta/v1/server-time from the first reachable backend.
- Merge the Jolokia surface (/metrics/v2/read, /metrics/v2/list,
  /metrics/v1/mbeans): objects union, numeric attributes sum by default, and
  Min/Max/Uptime/StartTime plus the distribution stats take a bound or a mean.
- Route /nodes extract-count queries to the summing path ahead of the certname
  merge, and give /resources aggregates the same path.
- Document the endpoints and merge semantics in the README.
- Cover version disagreement, metric rules, escaped MBean names, count summing
  and the non-aggregate /nodes merge with httptest backends.
2026-09-05 20:41:35 +10:00
benvin 1ee7a2c07c Merge pull request 'config: drop primary/prefer and treat all backends equally' (#9) from benvin/drop-primary into main
ci/woodpecker/tag/docker Pipeline was successful
Reviewed-on: #9
v0.2.0
2026-09-05 16:07:37 +10:00
unkin-agent 8ad6205200 docs: reword reports/events union without old/new framing
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
2026-09-05 13:49:02 +10:00
unkin-agent 2391f56a11 config: drop primary/prefer and treat all backends equally
- unmerged /pdb/query/v4/* paths now go to the first backend that answers, not a designated primary
2026-09-05 13:49:02 +10:00
benvin ffc2499f98 Merge pull request 'Support a config file alongside env vars in containers' (#10) from benvin/config-file-and-env into main
Reviewed-on: #10
2026-09-05 13:42:17 +10:00
benvin d724cf0a5e Merge pull request 'feat: sum aggregate rows across backends on event-counts and /reports' (#8) from benvin/aggregate-sums into main
Reviewed-on: #8
2026-09-05 13:06:44 +10:00
unkin-agent b1ecbf31ac feat: sum aggregate rows across backends on event-counts and /reports
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
- group by the row's non-aggregate fields and add the numeric columns; X-Records on a summed endpoint is the merged row count
2026-09-05 12:29:48 +10:00
unkin-agent 03174f5ea0 Support a config file alongside env vars in containers
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
- --config / PDBMUX_CONFIG select the file; /etc/pdbmux/config.yaml joins the default search order
2026-09-05 12:29:14 +10:00
benvin 4bb44fb331 Merge pull request 'docs: strip over-commenting from README and source' (#6) from benvin/comment-cleanup into main
Reviewed-on: #6
2026-09-05 12:22:52 +10:00
unkin-agent 6ce903a6eb merge main
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
2026-09-05 11:52:24 +10:00
benvin cb05c7f377 Merge pull request 'config: drop estate-specific defaults and docs' (#7) from benvin/generic-config into main
Reviewed-on: #7
2026-09-05 11:47:20 +10:00
unkin-agent ee82b72733 Merge origin/main into benvin/generic-config
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
Keep the generic wording for the package doc, --help text and README intro
while taking the /reports and /events merge from #5.
2026-09-05 11:44:28 +10:00
unkin-agent 7b9082de08 docs: strip over-commenting from server.go and reports.go
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
2026-09-05 11:42:43 +10:00
unkin-agent d88db498c0 Merge origin/main into benvin/comment-cleanup 2026-09-05 11:41:38 +10:00
unkin-agent 9d5e9d0ed8 config: drop estate-specific defaults and docs
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
Remove hardcoded internal PuppetDB URLs and site-specific wording so the
project is publishable as-is.

- backends have no default; require config file or PDBMUX_BACKENDS
- primary/prefer default to the first configured backend
- config init writes example.com placeholders
- Load no longer validates, so config init/version work unconfigured
- genericise README, package doc, help text and Dockerfile comment
2026-09-05 11:40:05 +10:00
benvin 14d119f8e8 Merge pull request 'feat: merge /reports and /events across both PuppetDBs' (#5) from benvin/reports-merge into main
Reviewed-on: #5
2026-09-05 11:38:31 +10:00
unkin-agent 31ad4ae457 docs: strip over-commenting from README and source
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
2026-09-05 11:38:24 +10:00
unkin-agent 01d87412ee fix: never dedupe hash-less report rows across backends
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
An extract/count()/group_by query returns synthetic rows with no report
hash, which reportKey fell back to keying by verbatim raw bytes. Two
backends emitting a byte-identical aggregate row (e.g.
{"status":"changed","count":1}) therefore collapsed into one, silently
undercounting the merged result and contradicting the documented
guarantee that no backend's rows are dropped.

Give the mergeUnion key func an ok return: false means the record has no
dedupe identity and is always kept. reportKey returns ok=false for
hash-less rows; hash-keyed report dedupe and event verbatim-identity
dedupe are unchanged.

Add TestMergeUnion_IdenticalHashlessRowsAreNotCollapsed covering the
collision case, and reword the README line to say aggregate rows pass
through even when byte-identical.
2026-09-05 11:33:34 +10:00
unkin-agent ed2e5b73d6 feat: merge /reports and /events across both PuppetDBs
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
Reports are immutable history, so a node that migrated has reports in the
old PuppetDB and the new one; serve the union rather than picking a single
owning backend as /facts does.

Re-apply order_by/limit/offset over the merged set and sum X-Records, since
each backend only orders and pages its own slice.
2026-09-05 11:22:36 +10:00
benvin e2e9004784 Merge pull request 'ci: add buildkit_config CA trust for artifactapi push' (#4) from benvin/buildx-ca-config into main
Reviewed-on: #4
2026-08-15 18:47:07 +10:00
unkin-agent a7e5a143f6 ci: add buildkit_config CA trust for artifactapi push
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
2026-08-15 18:31:05 +10:00
benvin 9fc928ee67 Merge pull request 'ci: use CA-baked plugin-docker-buildx image for artifactapi push' (#3) from benvin/buildx-ca-plugin-image into main
Reviewed-on: #3
2026-08-15 18:19:14 +10:00
unkin-agent 3c7251cc1e ci: use CA-baked plugin-docker-buildx image for artifactapi push
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
The upstream woodpeckerci/plugin-docker-buildx image does not trust the
internal CA, so buildx pushes to the artifactapi local docker registry
fail on TLS verification. Switch the docker push step to the CA-baked
plugin-docker-buildx image published to docker-internal, which bundles
the internal CA and pushes cleanly.
2026-08-15 18:04:23 +10:00
benvin c5b8b3824a Merge pull request 'ci: push images to artifactapi registry instead of gitea' (#2) from benvin/push-artifactapi into main
Reviewed-on: #2
2026-07-30 20:55:07 +10:00
unkinben f7fda175e6 ci: push images to artifactapi registry instead of gitea
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
Hard switch of the docker push target from the Gitea registry to the
artifactapi local docker registry (docker-internal); the Gitea VM and its
registry are being retired. Drops the droneci/DRONECI_PASSWORD creds since
artifactapi accepts unauthenticated in-cluster pushes. Also updates the README image path.

Claude-Session: https://claude.ai/code/session_015ur3i7D2azsMAWTSVABApv
2026-07-30 00:34:59 +10:00
benvin 85c1506450 Merge pull request 'Add pdbmux: merging PuppetDB proxy daemon' (#1) from benvin/initial into main
ci/woodpecker/tag/docker Pipeline was successful
Reviewed-on: #1
v0.1.0
2026-07-24 23:34:29 +10:00
benvin dda6b8c8c8 Add pdbmux: merging PuppetDB proxy daemon
ci/woodpecker/pr/build Pipeline was successful
ci/woodpecker/pr/pre-commit Pipeline was successful
ci/woodpecker/pr/test Pipeline was successful
Split out from node-lookup PR #17 into its own repo. pdbmux presents a
single merged PuppetDB v4 query surface over the old (Consul) and new
(k8s) PuppetDBs during the VM to k8s migration, and is deployed in-cluster
via argocd-apps as a container image.
2026-07-24 23:25:43 +10:00
gitadmin 9eabb06ba0 Initial commit 2026-07-24 23:23:33 +10:00