Documentation
¶
Index ¶
- Variables
- func ApplyExtraPorts(content string, extraPorts []string) string
- func ApplyImage(content, image string) string
- func BindForLAN(content string, lanExposed bool) string
- func BuildCustomImage(siteName, projectPath string, cfg *config.ContainerConfig) error
- func BuildCustomImageTo(siteName, projectPath string, cfg *config.ContainerConfig, w interface{ ... }) error
- func BuildFPMImage(version string, local bool) error
- func BuildFPMImageTo(version string, local bool, w io.Writer) error
- func BundledExtensions() []string
- func Cmd(args ...string) *exec.Cmd
- func ContainerBaseImage(projectPath string, cfg *config.ContainerConfig) string
- func ContainerExists(name string) (bool, error)
- func ContainerRunning(name string) (bool, error)
- func ContainerRunningQuiet(name string) bool
- func ContainerfileHash() (string, error)
- func CurrentImage(content string) string
- func CustomContainerName(siteName string) string
- func CustomImageExists(siteName string) bool
- func CustomImageName(siteName string) string
- func CustomImageUpToDate(siteName, projectPath string, cfg *config.ContainerConfig) bool
- func DaemonReload() error
- func DetectHostGatewayIP() string
- func DetectHostGatewayIPProbeOnly() string
- func EnsureNetwork(name string) error
- func EnsureNetworkDNS(name string, servers []string) error
- func EnsurePathMounted(path, phpVersion string)
- func EnsureUserIni(version string) error
- func EnsureXdebugIni(version string) error
- func ExtraVolumePaths() []string
- func GenerateCustomContainerQuadlet(siteName, projectPath string, port int) string
- func GenerateCustomQuadlet(svc *config.CustomService) string
- func GetQuadletTemplate(name string) (string, error)
- func HasContainerfile(projectPath string) bool
- func HostReachable(ip string) bool
- func ImageExists(image string) bool
- func InjectExtraVolumes(content string, paths []string) string
- func NeedsFPMRebuild() bool
- func NetworkGateway(name string) string
- func NormaliseXdebugMode(raw string) (string, error)
- func OCIRuntime() string
- func PodmanBin() string
- func PullImageTo(image string, w io.Writer) error
- func QuadletInstalled(name string) bool
- func ReadHostGatewayFromFile() string
- func RebuildFPMImage(version string, local bool) error
- func RebuildFPMImageTo(version string, local bool, w io.Writer) error
- func RemoveContainer(name string)
- func RemoveContainerfileHash(siteName string)
- func RemoveCustomContainer(siteName string)
- func RemoveCustomContainerQuadlet(siteName string) error
- func RemoveCustomImage(siteName string) error
- func RemoveQuadlet(name string) error
- func ResolveBuildContext(projectPath string, cfg *config.ContainerConfig) string
- func ResolveContainerfile(projectPath string, cfg *config.ContainerConfig) string
- func RestartUnit(name string) error
- func RewriteFPMQuadlets() error
- func Run(args ...string) (string, error)
- func RunSilent(args ...string) error
- func ServiceImage(quadletName string) string
- func ServiceVersion(quadletName string) string
- func StartUnit(name string) error
- func StopUnit(name string) error
- func StoreContainerfileHash(siteName, projectPath string, cfg *config.ContainerConfig)
- func StoreFPMHash() error
- func StripInstallSection(content string, autostartDisabled bool) string
- func UnitStatus(name string) (string, error)
- func WaitReady(service string, timeout time.Duration) error
- func WriteContainerHosts() error
- func WriteCustomContainerQuadlet(siteName, projectPath string, port int) error
- func WriteFPMQuadlet(version string) error
- func WriteQuadlet(name, content string) error
- func WriteQuadletDiff(name, content string) (changed bool, err error)
- func WriteXdebugIni(version, mode string) error
- type ContainerCache
Constants ¶
This section is empty.
Variables ¶
var AfterQuadletWriteFn func(name, content string) error
AfterQuadletWriteFn, if non-nil, is called by WriteQuadletDiff after writing the .container file. On macOS it is set to the launchd plist writer so both formats stay in sync (the .container file is the canonical source of truth; the plist is the live runtime unit).
var AfterUnitChange func(name string)
StartUnit starts a service unit. On Linux it first clears any lingering failed state from a previous run so that units which hit Restart= rate-limit (e.g. workers that raced container readiness in a buggy upgrade) recover automatically on the next `lerd start` instead of staying stuck in `failed`. AfterUnitChange is fired after every successful StartUnit / StopUnit / RestartUnit call. lerd-ui wires this at startup to invalidate the systemctl unit cache and publish "sites"/"services" events to the eventbus so every browser tab updates in real time — regardless of whether the mutation came from an HTTP handler, the CLI, the MCP server, or the file watcher. Nil by default so unit tests and binaries that don't run the UI don't pay the cost.
var Cache = &ContainerCache{ running: make(map[string]bool), interval: 15 * time.Second, refresh: make(chan struct{}, 1), pollFn: defaultPollFn, }
Cache is the process-wide container state store. Start it once from serve-ui; CLI commands that don't call Start fall back to direct podman inspect.
var DaemonReloadFn func() error = DaemonReload
DaemonReloadFn reloads the service manager after a unit file change. Defaults to systemctl --user daemon-reload. Override this on macOS with a no-op.
var RemoveContainerUnitFn func(name string) error
RemoveContainerUnitFn removes the platform-specific container unit file. On macOS this is set to services.Mgr.RemoveContainerUnit to remove the launchd plist. Nil on Linux (quadlet removal is sufficient).
var SkipQuadletUpToDateCheck bool
SkipQuadletUpToDateCheck disables the early-return optimisation in WriteFPMQuadlet that skips writing when the .container file is unchanged. Set to true on macOS where the unit file is a launchd plist, not a quadlet.
var UnitLifecycle interface { Start(name string) error Stop(name string) error Restart(name string) error UnitStatus(name string) (string, error) }
UnitLifecycle is the interface for starting, stopping, restarting, and querying service units. Set by the platform service manager on macOS so that StartUnit/StopUnit/RestartUnit/UnitStatus route through launchd instead of systemctl. Nil on Linux (the systemctl fallback is used).
var WriteContainerUnitFn func(name, content string) error = WriteQuadlet
WriteContainerUnitFn writes a container unit file for the given name and content. Defaults to writing a systemd quadlet (.container) file. Override this on macOS to write a launchd plist instead.
Functions ¶
func ApplyExtraPorts ¶ added in v1.0.0
ApplyExtraPorts appends extra PublishPort lines to quadlet content.
func ApplyImage ¶ added in v1.12.0
ApplyImage replaces the Image= line in quadlet content with the given image. If content contains no Image= line it is returned unchanged.
func BindForLAN ¶ added in v1.8.0
BindForLAN rewrites every PublishPort= line in a quadlet so the host-side bind matches the requested LAN-exposure state. The embedded quadlet files use the unprefixed `PublishPort=80:80` form, which podman interprets as binding 0.0.0.0 (all interfaces). When lanExposed is false (the default safe-on-coffee-shop-wifi state) we rewrite each unprefixed line to `PublishPort=127.0.0.1:80:80` so only the local host can connect; when true, we leave the unprefixed form alone so LAN clients can reach the service.
Lines that already have an explicit IP prefix (lerd-dns binds 127.0.0.1 directly because the LAN path goes through the userspace forwarder, not the publish) are left untouched in both states.
func BuildCustomImage ¶ added in v1.15.0
func BuildCustomImage(siteName, projectPath string, cfg *config.ContainerConfig) error
BuildCustomImage builds the OCI image for a site's custom container from the user's Containerfile. The image is tagged as lerd-custom-{siteName}:local.
func BuildCustomImageTo ¶ added in v1.15.0
func BuildCustomImageTo(siteName, projectPath string, cfg *config.ContainerConfig, w interface{ Write([]byte) (int, error) }) error
BuildCustomImageTo builds the custom image, writing progress to w.
func BuildFPMImage ¶ added in v0.1.14
BuildFPMImage builds the lerd PHP-FPM image for the given version if it doesn't exist. When local is false, it attempts to pull a pre-built base image from ghcr.io first.
func BuildFPMImageTo ¶ added in v0.5.6
BuildFPMImageTo builds the PHP-FPM image writing output to w. When local is false, it attempts to pull a pre-built base image from ghcr.io first.
func BundledExtensions ¶ added in v0.5.5
func BundledExtensions() []string
BundledExtensions returns the set of PHP extensions included in the default lerd FPM image.
func Cmd ¶ added in v1.12.0
Cmd returns an exec.Cmd for podman with the given arguments, using PodmanBin() so the binary is found even under launchd's restricted PATH.
func ContainerBaseImage ¶ added in v1.15.0
func ContainerBaseImage(projectPath string, cfg *config.ContainerConfig) string
ContainerBaseImage reads the Containerfile for a project and returns the base image from the first FROM instruction, e.g. "node:20-alpine". Returns "" if the file cannot be read or has no FROM line.
func ContainerExists ¶
ContainerExists returns true if the named container exists (running or not).
func ContainerRunning ¶
ContainerRunning returns true if the named container is running.
func ContainerRunningQuiet ¶ added in v1.15.1
ContainerRunningQuiet wraps ContainerRunning, swallowing the error and returning false when podman exec is unavailable.
func ContainerfileHash ¶ added in v0.1.25
ContainerfileHash returns the SHA-256 hash of the embedded PHP-FPM Containerfile. This is used to detect when images need to be rebuilt after a lerd update.
func CurrentImage ¶ added in v1.12.5
CurrentImage returns the value of the Image= line in quadlet content, or "" if no such line exists.
func CustomContainerName ¶ added in v1.15.0
CustomContainerName returns the Podman container name for a site's custom container, e.g. "lerd-custom-nestapp".
func CustomImageExists ¶ added in v1.15.0
CustomImageExists returns true when the local image for a site's custom container is present in the podman store.
func CustomImageName ¶ added in v1.15.0
CustomImageName returns the local image tag for a site's custom container, e.g. "lerd-custom-nestapp:local".
func CustomImageUpToDate ¶ added in v1.15.0
func CustomImageUpToDate(siteName, projectPath string, cfg *config.ContainerConfig) bool
CustomImageUpToDate returns true when the image exists and the stored Containerfile hash matches the current file on disk. Returns false when the image is missing, the hash file is missing, or the Containerfile has changed since the last build.
func DetectHostGatewayIP ¶ added in v1.13.1
func DetectHostGatewayIP() string
DetectHostGatewayIP returns an IP that is reachable from inside lerd-nginx and resolves to the host. Tries each candidate by opening a TCP connection to lerd-ui on port 7073 — only an IP that actually routes back to the host will succeed. The first working candidate wins. If none work, returns the legacy fallback so /etc/hosts is still well-formed; `lerd doctor` reports the failure so the user gets a real diagnosis instead of silent timeouts.
This replaces the previous "trust netavark" approach (PR #189), which trusted whatever `getent hosts host.containers.internal` returned without checking that the IP actually routed. On rootless Linux setups where netavark resolves to 169.254.1.2 but never wires up the bridge alias or DNAT for it, that IP is a dead end and Xdebug times out.
func DetectHostGatewayIPProbeOnly ¶ added in v1.15.1
func DetectHostGatewayIPProbeOnly() string
DetectHostGatewayIPProbeOnly is like DetectHostGatewayIP but returns "" when no candidate is actually reachable, instead of falling back to getent / the legacy constant. Used by `lerd doctor` to surface probe failures as a real diagnosis rather than the silent timeout Xdebug users otherwise see.
func EnsureNetwork ¶
EnsureNetwork creates the named Podman network if it does not already exist.
func EnsureNetworkDNS ¶ added in v1.0.3
EnsureNetworkDNS syncs the DNS servers on the named network to the provided list. It drops servers no longer present and adds new ones. This sets the upstream forwarders that aardvark-dns uses, which is necessary on systems where /etc/resolv.conf points to a stub resolver (e.g. 127.0.0.53) that is not reachable from inside the container network namespace.
func EnsurePathMounted ¶ added in v1.9.3
func EnsurePathMounted(path, phpVersion string)
EnsurePathMounted checks whether the given path is accessible inside the PHP-FPM and nginx containers. If the path is outside $HOME and not already volume-mounted, the quadlets are updated and containers restarted transparently before returning.
func EnsureUserIni ¶ added in v0.5.5
EnsureUserIni creates the per-version user php.ini with defaults if it doesn't exist. Same bind-mount race as EnsureXdebugIni: when this path is missing at FPM container start time, podman auto-creates it as a directory and the next EnsureUserIni call (which only Stat'd, didn't IsDir-check) silently no-ops while the user's php.ini is never written. Heal stale directories before returning the no-op fast path.
func EnsureXdebugIni ¶ added in v1.15.1
EnsureXdebugIni creates the xdebug ini file for the given PHP version if it doesn't already exist as a regular file. This prevents Podman from auto-creating a directory at the bind-mount source path when the container starts before the file is written.
func ExtraVolumePaths ¶ added in v1.9.3
func ExtraVolumePaths() []string
ExtraVolumePaths returns absolute paths that need to be bind-mounted into the PHP-FPM container because they are outside the user's home directory. It collects parked directories and linked site paths, deduplicates them, and returns only the top-level ancestors (so /var/www covers /var/www/app).
func GenerateCustomContainerQuadlet ¶ added in v1.15.0
GenerateCustomContainerQuadlet builds a quadlet .container file for a per-project custom container. The container joins the lerd network so it can reach services (lerd-mysql, lerd-redis, etc.) and is reachable by nginx via its container name.
func GenerateCustomQuadlet ¶ added in v0.5.4
func GenerateCustomQuadlet(svc *config.CustomService) string
GenerateCustomQuadlet builds a quadlet .container file for a custom service.
func GetQuadletTemplate ¶
GetQuadletTemplate returns the content of a named quadlet template file.
func HasContainerfile ¶ added in v1.15.0
HasContainerfile returns true when the project directory contains a Containerfile.lerd (the default custom container definition).
func HostReachable ¶ added in v1.15.1
HostReachable returns true when the given IP is reachable from lerd-nginx on the host probe port. Exported for the background watcher so it can cheaply verify whether the current /etc/hosts entry is still valid before running a full reprobe. Returns false when lerd-nginx isn't running.
func ImageExists ¶ added in v0.5.6
ImageExists returns true if the named image is present in the local store.
func InjectExtraVolumes ¶ added in v1.9.3
InjectExtraVolumes adds Volume= lines for paths that are not already covered by the %h:%h mount. Each path is bind-mounted read-write at the same location inside the container. Existing Volume= lines for the same host path are not duplicated.
func NeedsFPMRebuild ¶ added in v0.1.25
func NeedsFPMRebuild() bool
NeedsFPMRebuild returns true if the stored Containerfile hash differs from the current embedded Containerfile, meaning images should be rebuilt.
func NetworkGateway ¶ added in v0.1.14
NetworkGateway returns the gateway IP of the named Podman network. Falls back to "127.0.0.1" if it cannot be determined.
func NormaliseXdebugMode ¶ added in v1.16.0
NormaliseXdebugMode validates and canonicalises a user-supplied xdebug.mode value. Whitespace is trimmed, duplicates are dropped, and the result is a comma-separated string ready to be written into the ini file. An empty input returns "debug" so callers can use it as the default when enabling xdebug without an explicit mode.
func OCIRuntime ¶ added in v1.9.3
func OCIRuntime() string
OCIRuntime returns the name of the OCI runtime podman is currently configured to use.
func PodmanBin ¶ added in v1.12.0
func PodmanBin() string
PodmanBin returns the full path to the podman binary. On macOS it searches well-known Homebrew locations when PATH is restricted (e.g. launchd services).
func PullImageTo ¶ added in v0.5.6
PullImageTo pulls the named image, writing progress output to w.
func QuadletInstalled ¶ added in v0.1.17
QuadletInstalled returns true if a quadlet .container file exists for the given unit name.
func ReadHostGatewayFromFile ¶ added in v1.15.1
func ReadHostGatewayFromFile() string
ReadHostGatewayFromFile reads the current host.containers.internal IP from the bind-mounted /etc/hosts file that PHP-FPM containers see. Returns "" if the file is missing or the entry isn't present. Used by the watcher to compare on-disk state against a fresh probe without rewriting the file when nothing has changed.
func RebuildFPMImage ¶ added in v0.1.17
RebuildFPMImage force-removes and rebuilds the PHP-FPM image for the given version. When local is false, it attempts to pull a pre-built base image from ghcr.io first.
func RebuildFPMImageTo ¶ added in v0.5.6
RebuildFPMImageTo force-rebuilds the PHP-FPM image writing output to w. When local is false, it attempts to pull a pre-built base image from ghcr.io first.
func RemoveContainer ¶ added in v1.5.0
func RemoveContainer(name string)
RemoveContainer removes a stopped Podman container by name, ignoring errors if the container does not exist.
func RemoveContainerfileHash ¶ added in v1.15.0
func RemoveContainerfileHash(siteName string)
RemoveContainerfileHash removes the stored hash for a site.
func RemoveCustomContainer ¶ added in v1.15.0
func RemoveCustomContainer(siteName string)
RemoveCustomContainer removes the stopped container for a site's custom container (force-remove to handle edge cases).
func RemoveCustomContainerQuadlet ¶ added in v1.15.0
RemoveCustomContainerQuadlet removes the unit file for a custom container. On Linux this removes the systemd quadlet; on macOS the launchd plist.
func RemoveCustomImage ¶ added in v1.15.0
RemoveCustomImage removes the local image for a site's custom container.
func RemoveQuadlet ¶
RemoveQuadlet removes a Podman quadlet container unit file.
func ResolveBuildContext ¶ added in v1.15.0
func ResolveBuildContext(projectPath string, cfg *config.ContainerConfig) string
ResolveBuildContext returns the build context directory for a custom container build. Defaults to the project root.
func ResolveContainerfile ¶ added in v1.15.0
func ResolveContainerfile(projectPath string, cfg *config.ContainerConfig) string
ResolveContainerfile returns the absolute path to the Containerfile for a project. If cfg specifies a Containerfile it is resolved relative to projectPath; otherwise the default "Containerfile.lerd" is used.
func RewriteFPMQuadlets ¶ added in v1.9.3
func RewriteFPMQuadlets() error
RewriteFPMQuadlets regenerates the quadlet files for all installed PHP-FPM versions and the nginx quadlet. Call this when parked directories or site paths change so that extra volume mounts stay in sync.
func ServiceImage ¶ added in v0.5.6
ServiceImage returns the OCI image name embedded in a named quadlet template. Returns "" if the quadlet or Image line is not found.
func ServiceVersion ¶ added in v1.6.0
ServiceVersion extracts the major version from a built-in service's image tag. For example: mysql:8.0 → "8.0", postgis/postgis:16-3.5-alpine → "16", redis:7-alpine → "7", meilisearch:v1.7 → "1.7". Returns "" if the version cannot be determined.
func StoreContainerfileHash ¶ added in v1.15.0
func StoreContainerfileHash(siteName, projectPath string, cfg *config.ContainerConfig)
StoreContainerfileHash persists the MD5 hash of the current Containerfile so subsequent link calls can skip the build when the file hasn't changed.
func StoreFPMHash ¶ added in v0.1.25
func StoreFPMHash() error
StoreFPMHash writes the current Containerfile hash to disk.
func StripInstallSection ¶ added in v1.9.0
StripInstallSection removes the [Install] section from a quadlet's content when autostartDisabled is true, and returns the input unchanged when false.
Quadlets are special: a `[Install] WantedBy=default.target` clause causes the podman-system-generator to create a symlink in `/run/user/$UID/systemd/generator/default.target.wants/` on every daemon-reload, which makes the unit auto-start at login regardless of `systemctl --user enable/disable` (those don't apply to generator units). The only way to actually stop a quadlet from auto-starting is to drop the [Install] section from the source .container file before the generator sees it. WriteQuadletDiff calls this centrally so every code path that writes a quadlet (install, services, MCP server, custom-service generator) honours the global autostart setting without each having to remember.
func UnitStatus ¶
UnitStatus returns the active state of a service unit.
func WaitReady ¶ added in v1.2.2
WaitReady polls until the named service is ready to accept connections, or timeout is reached. Readiness is tested by running a lightweight probe inside the container: mysqladmin ping for mysql, pg_isready for postgres. For other services it falls back to waiting until the systemd unit is "active".
func WriteContainerHosts ¶ added in v1.2.4
func WriteContainerHosts() error
WriteContainerHosts writes the shared /etc/hosts bind-mounted into every PHP-FPM container. host.containers.internal uses an IP that has been verified reachable from inside lerd-nginx; .test domains point at lerd-nginx directly on the lerd bridge network.
func WriteCustomContainerQuadlet ¶ added in v1.15.0
WriteCustomContainerQuadlet writes the quadlet for a custom container site.
func WriteFPMQuadlet ¶ added in v0.4.0
WriteFPMQuadlet writes the systemd quadlet for a PHP-FPM version and reloads the systemd daemon if the content changed. It also ensures the xdebug and user ini files exist.
func WriteQuadlet ¶
WriteQuadlet writes a Podman quadlet container unit file. Before writing it applies BindForLAN to rewrite PublishPort= lines according to the current cfg.LAN.Exposed setting. This is done centrally here so callers (install, services, MCP server, custom-service generator) all get the same loopback-by-default treatment without each having to remember.
func WriteQuadletDiff ¶ added in v1.8.0
WriteQuadletDiff writes a quadlet like WriteQuadlet, but also reports whether the on-disk file actually changed. Callers can use this to daemon-reload + restart only the units that need it (e.g. lerd install rewriting binds from 0.0.0.0 to 127.0.0.1 when migrating to a build where lan:expose defaults to off — without a restart the running container would silently keep its old bind).
func WriteXdebugIni ¶ added in v0.4.0
WriteXdebugIni writes the per-version xdebug ini to the host config dir. The file is volume-mounted into the FPM container at /usr/local/etc/php/conf.d/99-xdebug.ini. An empty mode writes xdebug.mode=off (extension loaded but inactive); any other value is emitted as-is, so callers can pass "debug", "coverage", "debug,coverage", etc.
Types ¶
type ContainerCache ¶ added in v1.12.6
type ContainerCache struct {
// contains filtered or unexported fields
}
ContainerCache polls podman for container states on a configurable interval and serves reads from an in-memory snapshot. One background goroutine does all the work; every other caller reads from the map without spawning any subprocesses.
func (*ContainerCache) PollNow ¶ added in v1.12.6
func (c *ContainerCache) PollNow()
PollNow runs a synchronous poll and updates the in-memory state before returning. Use this when the caller needs current data immediately (e.g. the initial WebSocket snapshot). Unlike Refresh, it blocks until done.
func (*ContainerCache) Refresh ¶ added in v1.12.6
func (c *ContainerCache) Refresh()
Refresh schedules an immediate re-poll on the background goroutine. Returns without blocking; at most one pending refresh is queued.
func (*ContainerCache) Running ¶ added in v1.12.6
func (c *ContainerCache) Running(name string) bool
Running returns true if the named container is currently running. If the cache has not been started (CLI context), it falls back to a direct podman inspect so one-off commands still work correctly.
func (*ContainerCache) SetInterval ¶ added in v1.12.6
func (c *ContainerCache) SetInterval(d time.Duration)
SetInterval changes the background polling interval. Safe to call from any goroutine.
func (*ContainerCache) Start ¶ added in v1.12.6
func (c *ContainerCache) Start(ctx context.Context)
Start launches the background refresh loop. Safe to call only once.