Add pdbmux: a merging PuppetDB proxy for the VM->k8s migration #17
Reference in New Issue
Block a user
Delete Branch "benvin/pdbmux"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Why
During the VM→k8s Puppet migration there are two PuppetDBs — the legacy Consul-registered
http://puppetdbapi.service.consul:8080and the new k8shttps://puppetdb.k8s.syd1.au.unkin.net— and nodes move from one to the other as they migrate.node-lookupandpblastreportneed a single, consistent merged view without having to know (or query twice) which PuppetDB a given node currently lives in.This adds
pdbmux, a small HTTP daemon that fronts both backends and serves one merged PuppetDB v4 query surface.Changes
cmd/pdbmux/(config.go,merge.go,server.go,main.go): a cobra tool whose default action (alsoserve) starts the proxy, plusconfig init/config showandversionsubcommands, following the repo's config precedence pattern (defaults < config file < envPDBMUX_*< flags).GET /pdb/query/v4/nodes: dedupes bycertname, keeping the record with the newerreport_timestamp.GET /pdb/query/v4/factsat node granularity: keeps all facts from the backend owning eachcertname, chosen by the freshness strategy (per-certnamereport_timestampmap from/nodes, cached forfreshness_ttl, default 30s) or a static prefer-backend fallback.502only when both fail; passes records through as raw JSON so unknown fields survive./pdb/query/v4/*path to the configurable primary, and exposes/healthzwith per-backend reachability (200 ok/200 degraded/503 down).go test -race, no network) covering merge logic (both-have-node newer-wins, one-backend-only, one-backend-down, both-down 502), handler behaviour withhttptestbackends, query-param passthrough, and config precedence/validation.pdbmuxinto build/release:MakefileBINARIES,scripts/build-rpm.sh, nfpm packaging (binary + completions + a systemd unit), and the release pipeline's cross-platform build + Gitea asset list.pdbmuxin a newREADME.mdand updatesAGENTS.md.Config example
Env overrides:
PDBMUX_LISTEN,PDBMUX_PRIMARY,PDBMUX_MERGE,PDBMUX_PREFER,PDBMUX_TIMEOUT,PDBMUX_FRESHNESS_TTL,PDBMUX_BACKENDS(name=url,name=url).Merge semantics
/nodes— dedupe bycertname; strictly-newerreport_timestampwins; ties/single-backend nodes fall back toprefer./facts— percertname, keep all facts from one backend: the one holding that node's newer report (freshness, from a short-TTL/nodesmap) or thepreferbackend (static). A node present in only one backend always appears.primary; only GET is proxied.502.Verification
go build ./...,go vet ./...,go test -race ./...all pass;gofmtclean; pre-commit hooks pass.make build+make completionsbuild all four binaries and pdbmux completions;scripts/build-rpm.shproduces an RPM containing/usr/bin/pdbmux, the systemd unit, and completions./healthz→{"status":"ok"}with both backendsok;/nodesand/factsproxy and merge (HTTP 200).Deployment
Ships an RPM (
/usr/bin/pdbmux+pdbmux.servicereading/etc/pdbmux/config.yaml) suited to run as a systemd daemon on a VM during migration. The same static binary is container-ready for a future k8s deployment (single listener,/healthzprobe,PDBMUX_*env config).Rework: pdbmux is now a k8s container, not a per-VM RPM/systemd service
Per the all-in-kubernetes estate direction, pdbmux (a long-running daemon) now
ships as an in-cluster container image instead of an RPM-installed systemd unit
on each VM. The RPM remains the workstation/VM CLI package only.
Removed
packaging/pdbmux.service(systemd unit, DynamicUser) deleted./usr/bin/pdbmux,the systemd unit, or pdbmux completions;
build-rpm.shno longer builds/listsit. Verified
rpm -qlpshows only node-lookup/pburl/pblastreport (+ theircompletions).
Added
Dockerfile.pdbmux— staticCGO_ENABLED=0binary ongcr.io/distroless/static-debian12:nonroot,EXPOSE 8080,ENTRYPOINT ["pdbmux","serve"](mirrors encapi's image style). Builds clean..woodpecker/docker.yaml— onv*tags,woodpeckerci/plugin-docker-buildxbuilds and pushes
git.unkin.net/unkin/pdbmux:<tag>+:latestusing thedroneci/DRONECI_PASSWORDcredentials (same mechanism/secret as encapi).k8s resources + serviceAccountName set.
Kept
make buildand covered bygo test -race ./....Docs
PDBMUX_*env(no config file in-cluster); image + argocd-apps deployment described.
Verification
go build ./...OK,go test -race ./...OK,go vet ./cmd/pdbmux/...OK.make buildbuilds all four binaries;build-rpm.shproduces a clean RPMwithout any pdbmux/systemd files.
docker build -f Dockerfile.pdbmuxsucceeds; entrypoint ispdbmux serve.The k8s Deployment/Service/Gateway manifests are in a companion
argocd-appsPR(namespace
pdbmux, exposed atpdbmux.k8s.syd1.au.unkin.net). That PR is gatedon this one merging and a
v*tag being cut so the image exists.unkinben referenced this pull request from unkin/argocd-apps2026-07-24 23:12:28 +10:00
pdbmux has moved to its own repository: https://git.unkin.net/unkin/pdbmux (initial content PR: unkin/pdbmux#1). Closing this PR — the code is preserved there. node-lookup stays a CLI/RPM-only module.
Pull request closed