fix(cli): ignore a half-populated socket activation environment (#11394)

A container engine started from a socket-activated system unit leaks a bare
LISTEN_PID into every container it spawns, with no matching LISTEN_FDS. LocalAI
read that as a malformed activation attempt and refused to start:

    ERROR Error running the application error=loading systemd socket
    activation listeners: invalid LISTEN_FDS ""

systemd's own sd_listen_fds() treats either variable being absent as "not
activated" rather than as an error, so do the same and fall back to ordinary
--address binding. A value that is present but malformed is still rejected, so
a real activation attempt cannot silently bind the wrong socket.

Fixes #11390


Assisted-by: Claude:claude-opus-5 [golangci-lint]

Signed-off-by: Ettore Di Giacinto <mudler@localai.io>
Co-authored-by: Ettore Di Giacinto <mudler@localai.io>
This commit is contained in:
mudler's LocalAI [bot]andEttore Di Giacinto authored and GitHub committed 2026-08-06 17:35:23 +02:00
1 parent 5ac445e1d4
commit 8052c950cf
3 files changed
+41

No files matched your search

+8
View File
@@ -24,6 +24,14 @@ func systemdActivatedListeners() ([]net.Listener, error) {
}
}()
// A half-populated environment is not an activation attempt. Container runtimes
// started from a socket-activated system unit leak a bare LISTEN_PID into every
// container they spawn, and systemd's own sd_listen_fds() treats either variable
// being absent as "not activated" rather than as an error.
if listenPID == "" || listenFDs == "" {
return nil, nil
}
pid, err := strconv.Atoi(listenPID)
if err != nil {
return nil, fmt.Errorf("invalid LISTEN_PID %q: %w", listenPID, err)
+28
View File
@@ -85,6 +85,34 @@ var _ = Describe("systemdActivatedListeners", func() {
Expect(os.Getenv("LISTEN_FDNAMES")).To(BeEmpty())
})
It("binds normally when the environment leaks LISTEN_PID without LISTEN_FDS", func() {
Expect(os.Setenv("LISTEN_PID", strconv.Itoa(os.Getpid()))).To(Succeed())
Expect(os.Unsetenv("LISTEN_FDS")).To(Succeed())
DeferCleanup(func() {
_ = os.Unsetenv("LISTEN_PID")
})
listeners, err := systemdActivatedListeners()
Expect(err).NotTo(HaveOccurred())
Expect(listeners).To(BeEmpty())
Expect(os.Getenv("LISTEN_PID")).To(BeEmpty())
})
It("binds normally when the environment leaks LISTEN_FDS without LISTEN_PID", func() {
Expect(os.Unsetenv("LISTEN_PID")).To(Succeed())
Expect(os.Setenv("LISTEN_FDS", "1")).To(Succeed())
DeferCleanup(func() {
_ = os.Unsetenv("LISTEN_FDS")
})
listeners, err := systemdActivatedListeners()
Expect(err).NotTo(HaveOccurred())
Expect(listeners).To(BeEmpty())
Expect(os.Getenv("LISTEN_FDS")).To(BeEmpty())
})
It("reports malformed activation metadata instead of silently binding another socket", func() {
Expect(os.Setenv("LISTEN_PID", strconv.Itoa(os.Getpid()))).To(Succeed())
Expect(os.Setenv("LISTEN_FDS", "not-a-number")).To(Succeed())
+5
View File
@@ -111,6 +111,11 @@ For a Podman-managed container, configure Podman to preserve and pass the
systemd socket file descriptor into the container. The LocalAI process inside
the container consumes the same activation protocol.
Activation needs both `LISTEN_PID` and `LISTEN_FDS`. If only one of them is set,
LocalAI ignores them and binds `--address` as usual. A container engine started
from a socket-activated system unit can leak a bare `LISTEN_PID` into every
container it spawns, and that is not an activation attempt.
## Next Steps
- [Try it out with examples](/basics/try/)