Make the service YAML the single source of truth for custom services#679
Merged
Conversation
Custom service install state was tracked in two places that could drift: ServiceInstalled keyed off the quadlet file while the services list, start, update, tuning and the rest read the per-service YAML. A quadlet with no YAML showed as installed in the preset picker yet was invisible everywhere else and never ran (issue #678). ServiceInstalled now resolves custom (non-default) services from their YAML, so the preset flag, the install guard and dependency checks agree with the services list. Built-in default presets keep the quadlet as their signal since they have no YAML by design. A reconcile pass on lerd start enforces the invariant both ways: regenerate a missing quadlet/plist from its YAML, and remove an orphan quadlet with no backing YAML (data dir left intact). Orphans are found by a marker stamped into managed quadlets plus the non-default preset names, so legacy orphans written before the marker are still reaped; site and worker quadlets are never touched. A running orphan is left in place rather than destroyed, and per-service errors no longer abort the rest of the pass. The install guard now blocks only a fully installed service so a partial remnant can be healed by reinstalling. Closes #678
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Problem
A custom service's install state was tracked in two places that could drift apart.
serviceops.ServiceInstalled(and therefore the preset picker'sinstalledflag, the install guard, and dependency checks) keyed off the quadlet file, while the services list,lerd start/stop, update, tuning, env, pause and host-proxy all read the per-service definition YAML. When a quadlet existed with no backing YAML, the preset picker reported the service as installed while it was invisible in every list, never started, and could not be managed. We found four such orphans on a real install (gotenberg, phpmyadmin, stripe-mock, and a misclassified site container). Fixes #678.Change
The service definition YAML is now the single source of truth for custom (non-default) services.
ServiceInstalledresolves install state from the YAML for them, so the preset flag, the install guard and dependency checks agree with the services list. Built-in default presets keep the quadlet as their signal because their definition lives in the binary and they have no YAML.A reconciliation pass runs on
lerd startand enforces the invariant in both directions:Orphans are identified by a
# lerd-managed-servicemarker stamped into managed quadlets, unioned with the known non-default preset names so orphans written before the marker existed are still reaped. Site containers and per-site workers carry neither, so they are never touched. A running orphan is left in place rather than force-stopped and destroyed, and per-service errors are collected so one bad service can't abort the rest of the pass. The install guard now blocks only a fully installed service (YAML and unit both present), so a partial remnant from an interrupted install or remove can be healed by reinstalling.Closes #678