add warn on dnssd name collision change spec
This commit is contained in:
1 parent
30670de93b
commit
3910ab974c
5 files changed
+296
No files matched your search
@@ -0,0 +1,98 @@
|
||||
# Design
|
||||
|
||||
## Context
|
||||
|
||||
`entrypoint.sh` starts D-Bus, Avahi and cupsd, configures the managed queue
|
||||
(`lpadmin -D/-o/-E` on every start) and then verifies cupsd answers on TCP 631.
|
||||
Any queue present in cupsd — including ones added manually via the web UI — is
|
||||
advertised as the DNS-SD instance `"<Description> @ <host>"` (queue name when no
|
||||
Description is set). Avahi registers only one instance per name: with two
|
||||
queues deriving the same name, one is silently never advertised, and CUPS 2.4
|
||||
does not rename on collision (upstream `scheduler/dnssd.c`, `TODO:
|
||||
Handle collisions`). Clients that pinned the losing name (macOS stores it in
|
||||
the `dnssd://` device URI) then report the printer offline. See proposal.md for
|
||||
the incident. The container ships `cups-client` (guaranteed `lpstat`),
|
||||
`avahi-utils` and `curl` (Containerfile).
|
||||
|
||||
## Goals / Non-Goals
|
||||
|
||||
**Goals:**
|
||||
- At startup, detect when two or more queues would derive the same DNS-SD
|
||||
instance name and log an actionable warning naming the queues.
|
||||
- Keep the check strictly best-effort: it must never affect startup success or
|
||||
queue configuration (consistent with the existing warning style under
|
||||
`set -eu`).
|
||||
- Give operators a documented way to confirm and fix the condition by hand
|
||||
(README troubleshooting entry).
|
||||
|
||||
**Non-Goals:**
|
||||
- No automatic remediation (no renaming, no un-sharing, no deleting queues).
|
||||
- No change to how/when `lpadmin` runs — the restart re-registration churn is
|
||||
out of scope for this change.
|
||||
- No client-side tooling; the check runs only inside the container.
|
||||
|
||||
## Decisions
|
||||
|
||||
**D1 — Derive names from live cupsd data, not from mDNS.**
|
||||
The check compares *derived* instance names (`Description` or queue name per
|
||||
queue) instead of listening to actual Avahi registrations. Derivation is
|
||||
deterministic and race-free at startup; observing mDNS (`avahi-browse`) would
|
||||
depend on registration timing and only detect collisions after the fact.
|
||||
- *Alternative considered:* post-startup mDNS audit ("shared queue missing from
|
||||
advertisements") — catches more failure modes but is timing-sensitive and
|
||||
needs instance→queue mapping via TXT `rp`; rejected as the primary mechanism,
|
||||
still documented as a manual verification step in the README.
|
||||
|
||||
**D2 — Inputs: `LC_ALL=C lpstat -l -p` for names/Descriptions, `printers.conf`
|
||||
for the shared flag.**
|
||||
- Queue names + Descriptions come from `lpstat -l -p` run with `LC_ALL=C` so the
|
||||
`Description:` line parses regardless of container locale (the live value is
|
||||
authoritative — it is exactly what cupsd will register).
|
||||
- Only shared queues are advertised, so the shared flag comes from
|
||||
`/etc/cups/printers.conf` (`<Printer …>` block: `Shared yes`). When the flag
|
||||
cannot be determined (file not yet flushed after this run's `lpadmin`, queue
|
||||
missing from it), the queue is **treated as shared** — a collision warning
|
||||
for a not-yet-shared queue is still actionable, whereas staying silent on a
|
||||
shared one reproduces the original incident.
|
||||
- *Alternative considered:* `ipptool` Get-Printer-Attributes — richer data, but
|
||||
availability of `ipptool` in the image is not guaranteed by the Containerfile
|
||||
package list; rejected to keep the check dependency-free beyond `cups-client`.
|
||||
|
||||
**D3 — Placement and failure mode.**
|
||||
A `check_dnssd_name_collisions` function runs after the queue configuration
|
||||
blocks and the TCP reachability check, immediately before the final `ready`
|
||||
log line, so the warning is the last thing an operator sees in `podman logs`.
|
||||
It logs through the existing `log()` helper (`[entrypoint] warning: …`
|
||||
followed by indented detail lines, mirroring the TCP-631 error block) and never
|
||||
exits non-zero; every parse failure degrades to "check skipped" (the script
|
||||
runs under `set -eu`, so all command substitutions are guarded with `|| true`).
|
||||
|
||||
**D4 — Collision = exact match on the name base.**
|
||||
The `@ <host>` suffix is identical for every queue on the server, so equality
|
||||
is decided on the base alone; the full derived name (base + `@ <short-host>`)
|
||||
is still printed in the warning so it matches what `dns-sd -B` shows.
|
||||
The remedy text offers the two fixes that worked on the live system: give each
|
||||
queue a unique Description (`lpadmin -D`), or remove the redundant queue
|
||||
(`lpadmin -x`), followed by remove/re-add of the client queue (README details
|
||||
why clients must be re-added).
|
||||
|
||||
## Risks / Trade-offs
|
||||
|
||||
- [Queues created *after* startup are not re-checked] → acceptable: the check
|
||||
runs on every container start, and the README documents a manual
|
||||
`dns-sd -B _ipp._tcp` verification for live changes.
|
||||
- [Stale shared flag if `printers.conf` is not flushed in time] → mitigated by
|
||||
assuming shared when unknown (errs toward warning), see D2.
|
||||
- [False warning when a shared flag parse misreads a queue block] → parsing is
|
||||
scoped to `<Printer name>` … `</Printer>` blocks with exact keyword matches;
|
||||
a misread can at worst add a queue to the comparison, and the warning is
|
||||
advisory only.
|
||||
- [Warning becomes noise on intentionally duplicated setups] → duplication is
|
||||
never functional in CUPS/Avahi (one registrant always loses), so there is no
|
||||
legitimate configuration the warning would nag about.
|
||||
|
||||
## Migration Plan
|
||||
|
||||
Log-output-only change: deploy by rebuilding the image and restarting the
|
||||
container (normal quadlet cycle). No state, config or client impact; rollback
|
||||
is reverting `entrypoint.sh`/README.
|
||||
Reference in new issue
Block a user