Files
nomad/command/agent/sdnotify_linux.go
Arian van Putten d28af58cbb agent: implement sd-notify reload correctly (#25636)
First of all, we should not send the unix time, but the monotonic time.
Second of all, RELOADING= and MONOTONIC_USEC fields should be sent in
*single* message not two separate messages.

From the man page of [systemd.service](https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html#Type=)

> notification message via sd_notify(3) that contains the "RELOADING=1" field in
> combination with "MONOTONIC_USEC=" set to the current monotonic time (i.e.
> CLOCK_MONOTONIC in clock_gettime(2)) in μs, formatted as decimal string.

[sd_notify](https://www.freedesktop.org/software/systemd/man/latest/sd_notify.html)
now has code samples of the protocol to clarify.

Without these changes, if you'd set
Type=notify-reload on the agen'ts systemd unit, systemd
would kill the service due to the service not responding to reload
correctly.
2025-04-14 11:38:56 -04:00

50 lines
1.2 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
//go:build linux
package agent
import (
"fmt"
"io"
"net"
"os"
"time"
"golang.org/x/sys/unix"
)
const sdNotifySocketEnvVar = "NOTIFY_SOCKET"
// openNotify opens the systemd notify socket only if the expected env var has
// been set, because the systemd unit file is Type=notify or Type=notify-reload
// (systemd 253+). It then unsets the env var in the agent process so that child
// processes can't accidentally inherit it. This function returns (nil, nil) if
// the env var isn't set.
func openNotify() (io.WriteCloser, error) {
socketPath := os.Getenv(sdNotifySocketEnvVar)
if socketPath == "" {
return nil, nil
}
defer os.Unsetenv(sdNotifySocketEnvVar)
conn, err := net.DialTimeout("unixgram", socketPath, time.Second)
return conn, err
}
// sdNotify sends the message on the systemd notify socket, and gracefully
// handles a nil socket
func sdNotify(w io.Writer, msg string) {
if w == nil || msg == "" {
return
}
w.Write([]byte(msg))
}
func sdNotifyReloading(w io.Writer) {
var ts unix.Timespec
unix.ClockGettime(unix.CLOCK_MONOTONIC, &ts)
sdNotify(w, fmt.Sprintf("RELOADING=1\nMONOTONIC_USEC=%d", ts.Nano()/1000))
}