chore: improve Caddy Salt state with pillarization and graceful reload (#440) #441
No reviewers
Labels
No labels
domain:backend
domain:devops
domain:frontend
status:approved
status:in-progress
status:needs-fix
status:qa
type:bug
type:devops
type:feature
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set.
Reference
ldraney/pal-e-platform!441
Loading…
Add table
Add a link
Reference in a new issue
No description provided.
Delete branch "440-caddy-salt-improvements"
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?
Summary
Three quality improvements to the Caddy Salt state introduced in PR #439, preparing the template for multi-domain support (#434). Hardcoded Tailscale hostnames are replaced with pillar-driven variables, service restart is replaced with graceful reload, and the Caddyfile template now loops over pillar data.
Stacked PR: depends on PR #439 being merged first.
Changes
salt/states/caddy/Caddyfile.j2-- replaced hardcoded palinks.app site blocks with Jinja loop overpillar['caddy']['sites']; each site definesdomain,proxy_target, and optionalwww_redirectsalt/states/caddy/init.sls-- replacedservice.runningwithwatchwith acaddy-reloadstate usingcmd.run/onchangesfor zero-downtime config reloads; added expected pillar structure documentation in header comments; keptservice.runningfor boot-time enablement onlyExpected Pillar Structure
Test Plan
salt '*' state.apply caddy test=Trueto validateReview Checklist
Related Notes
ldraney/pal-e-platform #440-- the Forgejo issue this PR implementspal-e-platform-- infrastructure projectCloses #440
PR #441 Review
DOMAIN REVIEW
Tech stack identified: Salt (SLS states) + Jinja2 templates + Caddy web server configuration.
Salt compliance (against repo conventions):
kebab-case-descriptorpattern (caddy-caddyfile,caddy-service,caddy-reload) -- consistent with existing states liketailscaled-service,sshd-config,k3s-unit-file.file.managedblock includes all required fields (name,source,template,user,group,mode) -- matchessshd-configandk3s-unit-filepatterns..slsdocumentation conventions.Caddy configuration quality:
reverse_proxywithtls_server_namefor upstream TLS validation -- correct pattern for Tailscale backends.www_redirectusesredir ... permanent(301) -- appropriate for SEO and cache behavior.Salt state architecture (graceful reload):
service.runningwithwatch:on the Caddyfile, which triggers a full service restart on config change. PR #441 replaces this withcmd.run/onchangesusingcaddy reload, which is a zero-downtime reload. This is a meaningful improvement -- Caddy reload validates the new config before swapping, so a bad config does not take down the service.service.runningis retained for boot-time enablement only (enable: True) -- correct separation of concerns.Jinja template quality:
salt['pillar.get']('caddy:sites', {})with empty dict default -- correct; prevents template render failure if pillar is missing (renders an empty Caddyfile instead of crashing).site.get('www_redirect', false)-- uses.get()with default, correct for optional fields.sites.items()withsite_idvariable -- clean iteration pattern.BLOCKERS
1.
caddy-reloadruns as root with no user constraint (medium risk)The
cmd.runstate forcaddy reload --config /etc/caddy/Caddyfilewill execute as root by default. Caddy itself runs as thecaddyuser on most installations. While this works (root can reload Caddy), best practice is to be explicit about the execution context. This is not a hard blocker since the edge-proxy is a single-purpose node and Salt runs as root, but worth noting.Downgraded to NIT -- Salt states inherently run as root via the minion. This is consistent with the existing
k3sandsshstates in the repo.No blockers found. All BLOCKER criteria pass:
NITS
1.
caddy-servicehas no dependency oncaddy-caddyfile(minor)In
init.sls, thecaddy-servicestate (service.runningwithenable: True) has norequire:orwatch:relationship tocaddy-caddyfile. Salt evaluates states in declaration order by default, but an explicitrequirewould make the dependency chain clearer and protect against reordering:This ensures the Caddyfile is deployed before the service is enabled, which matters on first-run (fresh node).
2.
caddy-reloaddoes not validate config before reload (minor)caddy reloaditself validates the config before applying, so this is inherently safe. However, if validation fails, thecmd.runwill return a non-zero exit code and Salt will report it as a failed state. Consider addingcaddy validate --config /etc/caddy/Caddyfileas a separate state withprereq:to make validation failures more visible in Salt output. This is a nice-to-have, not a requirement.3. Jinja
falsevsFalse(cosmetic)Line
{%- if site.get('www_redirect', false) %}-- Jinja2 accepts bothfalseandFalse, but Python convention (and what Salt pillar YAML parses booleans as) isFalse. UsingFalsewould be more consistent with the Python/Salt ecosystem. Functionally identical.4. Missing trailing newline consideration (cosmetic)
The Caddyfile.j2 template ends with
{%- endfor %}using the whitespace-stripping tag (-%). This means the rendered file may not end with a trailing newline. Most tools expect a trailing newline. Consider using{% endfor %}(without-) for the final tag, or adding an explicit newline after the block.SOP COMPLIANCE
Closes #440present in PR bodyPROCESS OBSERVATIONS
Caddyfile.j2andinit.sls), so #439 must merge first or this PR will conflict. The dependency is correctly documented.caddy reloadpattern validates config before applying, and the pillar-driven approach means future domain additions are data-only changes (no template edits). Theonchangesguard ensures reload only fires when the Caddyfile actually changes.salt '*' state.apply caddy test=True") depends on pillar data existing. Since this PR does not add pillar data (that comes separately), the test plan should note that dry-run validation requires pillar data to be added first. This is documented implicitly ("After PR #439 merges and pillar data is added") but could be more explicit.VERDICT: APPROVED
58338d6d773615ffe682