Documentation ¶
Overview ¶
Package sd aims to make it easier to write simple network daemons for Linux systemd
https://www.freedesktop.org/software/systemd/man/daemon.html
Specifically it supports the following:
- Socket activation for standard standard net package Listeners and Packetconns, with minimal code changes.
- Notify the init system about startup completion or status updates via the sd_notify(3) interface.
- Using systemd FDSTORE to hold open file descriptors during restart.
- Systemd watchdog support
Package "sd" is not depended on systemd as such. If there's no socket activation available the fallback is most often to just create the socket. If there's no notifiy socket, calling sd.Notify() will of course fail.
You can use package "sd" without any interaction with systemd, merely to manage a set of active socket file descriptors using the Cleanup() function to close all file decriptors not in use and Reset() to make all file descriptors in use available for creating Listeners/PacketConns again. This can be used for simple daemon reload schemes to respawn a daemon keeping it's file descriptors open. (with or without systemd).
Index ¶
- Constants
- Variables
- func Cleanup()
- func Export(sdname string, f interface{}) (err error)
- func FileWith(sdname string, tests ...FileTest) (rfile *os.File, rname string, err error)
- func Forget(f interface{}) (err error)
- func InheritNamedListener(wantName string, tests ...FileTest) (l net.Listener, gotName string, err error)
- func InheritNamedPacketConn(wantName string, tests ...FileTest) (l net.PacketConn, gotName string, err error)
- func Listen(nett, laddr string) (net.Listener, error)
- func ListenFdsWithNames() (count int, names []string, err error)
- func ListenPacket(nett, laddr string) (net.PacketConn, error)
- func ListenTCP(nett string, laddr *net.TCPAddr) (*net.TCPListener, error)
- func ListenUDP(nett string, laddr *net.UDPAddr) (*net.UDPConn, error)
- func ListenUnix(nett string, laddr *net.UnixAddr) (*net.UnixListener, error)
- func ListenUnixgram(nett string, laddr *net.UnixAddr) (*net.UnixConn, error)
- func NamedListenTCP(name, nett string, laddr *net.TCPAddr) (l *net.TCPListener, err error)
- func NamedListenUDP(name, net string, laddr *net.UDPAddr) (*net.UDPConn, error)
- func NamedListenUnix(name, nett string, laddr *net.UnixAddr) (l *net.UnixListener, err error)
- func NamedListenUnixgram(name, nett string, laddr *net.UnixAddr) (l *net.UnixConn, err error)
- func Notify(flags int, lines ...string) (err error)
- func NotifyStatus(status int, message string) error
- func ReplaceProcess(sig syscall.Signal) (int, error)
- func ReplaceProcessEnv(sig syscall.Signal, env []string) (int, error)
- func Reset()
- func SetUnixSocketUnlinkPolicy(policy uint32)
- func SignalParentTermination() error
- func StartProcess(env []string) (int, error)
- func WatchdogEnabled() (enabled bool, when time.Duration)
- type FileTest
- func IsFifo(path string) FileTest
- func IsListening(want bool) FileTest
- func IsSoReusePort() FileTest
- func IsSocket(family, sotype int, listening int) FileTest
- func IsSocketInet(family int, sotype int, listening int, port uint16) FileTest
- func IsSocketUnix(sotype int, listening int, path *string) FileTest
- func IsTCPListener(addr *net.TCPAddr) FileTest
- func IsUDPListener(addr *net.UDPAddr) FileTest
- func IsUNIXListener(addr *net.UnixAddr) FileTest
Constants ¶
const ( // Never unlink socket files before listening UnixSocketUnlinkPolicyNone uint32 = iota // Always unlink socket files before listning UnixSocketUnlinkPolicyAlways // Always unlink, but stat(2) the file to ensure it's a UNIX socket before unlinking. UnixSocketUnlinkPolicySocket // Take a flock(2) lock on a socket.lock file before unlinking to ensure no other process is still using it. UnixSocketUnlinkPolicyFlock )
UnixScoketUnlinkPolicy* constants are used to decide how to deal with listening on a UNIX socket where the filesystem file might already exist. One way is to just unlink it, but it's hard to know whether there's still a process using it. The flock(2) advisory locking scheme deals with this in a nice way.
const ( // StatusNone - Don't send a STATUS StatusNone = iota // StatusReady - Tell systemd status is READY StatusReady // StatusReloading - Tell systemd status is RELOADING StatusReloading // StatusStopping - Tell systemd status is STOPPING StatusStopping // StatusWatchdog - Tell the systemd WATCHDOG we are alive StatusWatchdog )
Status* tells what status data to send to systemd over the nofity socket. You can control this in detail yourself by using the Notify() function.
const ( // NotifyUnsetEnv flag provided to Notify() to unset the systemd notify/Watchdog env vars NotifyUnsetEnv = 1 << iota // NotifyWithFds flag to Notify() to instruct it to send active file descriptors along with // systemd notify message to FDSTORE NotifyWithFds )
Variables ¶
var ErrNoSuchFdName = errors.New("No file with the requested name and no requested address")
ErrNoSuchFdName signals an attempt to create a socket without specifying an existing fd name or an address. UNIX sockets require a file system path and can not (like IP socket) listen on all addresses, so it's an error to not provide either a name, or a path.
var ErrSdNotifyNoSocket = errors.New("No systemd notify socket in environment")
ErrSdNotifyNoSocket is informs the caller that there's no NOTIFY_SOCKET available
Functions ¶
func Cleanup ¶
func Cleanup()
Cleanup closes all inherited file descriptors which have not yet been used by clients of this library by a directly or indirect call to FileWith() The network functions (Listen*, NamedListen*, InheritNamed*) for listening or inheriting sockets will indirectly call FileWith()
func Export ¶
Export records a dup() of the file descriptor and makes it managed by the sd package, marked as in active use. Closing the object provided will not close the managed file descriptor, so any socket connection will still be open an be able to be transferred to other processes/objects in open state.
If you want to stop managing the file descriptor and close it, call Forget() on the name, or provide the same object as was exported.
func FileWith ¶
FileWith returns any file descriptor (as an *os.File) which matches the given systemd name *and* any FileTests provided from the available pool of (inherited) file descriptors. The file descriptor is marked as no longer available and forgotten by the library. If the name requested is "", any file descriptor matching the tests is returned. The actual name is also returned FYI (in case the requested name was "")
The name provided here is *NOT* the same name as the calling .Name() on the returned file. This name is the systemd name as controlled by the systemd socket unit FileDescriptorName=
Calling .Name() on an socket *os.File will usually return information about bound addresses. That's not the name used here.
Notice: Once the file is returned, it's no longer the responsibility of the sd package, so any test to determine whether the file is actually the one you need should be defined and passed as a FileTest. You cannot get a file based on "half-a-test", do some more testing later and then regret and put it back. Write a FileTest function instead. If you want the sd library to track the returned file as in active use, call Export() on it.
func Forget ¶
func Forget(f interface{}) (err error)
Forget makes the sd library forget about its file descriptor (made by Export) associated with either an exported object or a string naming a file descriptor. If more file descriptors are named the same, they are all closed. Forget should be passed, either a string naming the file descriptor, OR the exact object originally exported.
func InheritNamedListener ¶
func InheritNamedListener(wantName string, tests ...FileTest) (l net.Listener, gotName string, err error)
InheritNamedListener returns a net.Listener and its systemd name passing the tests (and name criteria) provided. If there's no inherited FD which can be used the returned listener will be nil. The returned listener will be Export'ed by the sd library. Call Forget() to undo the export.
func InheritNamedPacketConn ¶
func InheritNamedPacketConn(wantName string, tests ...FileTest) (l net.PacketConn, gotName string, err error)
InheritNamedPacketConn returns a net.Listener and its systemd name passing the tests (and name criteria) provided. If there's no inherited FD which can be used the returned listener will be nil. The returned packetconn will be Export'ed by the sd library. Call Forget() to undo the export.
func Listen ¶
Listen returns a net.Listener like net.Listen, but will first check whether an inherited file descriptor is already listening before creating a new socket The returned listener will be Export'ed by the sd library. Call Forget() to undo the export.
func ListenFdsWithNames ¶
ListenFdsWithNames return the number of inherited filedescriptors and their names, along with any error occurring while inheriting them. Calling Reset() will reset these values too.
func ListenPacket ¶
func ListenPacket(nett, laddr string) (net.PacketConn, error)
ListenPacket returns a net.PacketConn like net.ListenPacket, but will first check whether an inherited file descriptor is already available before creating a new socket The returned packetconn will be Export'ed by the sd library. Call Forget() to undo the export.
func ListenTCP ¶
ListenTCP returns a normal *net.TCPListener. It will create a new socket if there's no appropriate inherited file descriptor listening. The returned listener will be Export'ed by the sd library. Call Forget() to undo the export.
func ListenUDP ¶
ListenUDP returns a normal *net.UDPConn. It will create a new socket if there's no appropriate inherited file descriptor listening. The returned listener will be Export'ed by the sd library. Call Forget() to undo the export.
func ListenUnix ¶
ListenUnix is like net.ListenUnix and will return a normal *net.UnixListener. It will create a new socket if there's no appropriate inherited file descriptor listening. The returned listener will be Export'ed by the sd library. Call Forget() to undo the export.
func ListenUnixgram ¶
ListenUnixgram returns a normal *net.UnixConn. It will create a new socket if there's no appropriate inherited file descriptor listening. The returned conn will be Export'ed by the sd library. Call Forget() to undo the export.
func NamedListenTCP ¶
NamedListenTCP is like ListenTCP, but requires the file descriptor used to have the given systemd socket name The returned listener will be Export'ed by the sd library. Call Forget() to undo the export.
func NamedListenUDP ¶
NamedListenUDP is like ListenUDP, but will require any used inherited file descriptor to have the given systemd socket name. The returned listener will be Export'ed by the sd library. Call Forget() to undo the export.
func NamedListenUnix ¶
NamedListenUnix is like ListenUnix, but will require any used inherited file descriptor to have the given systemd socket name The returned listener will be Export'ed by the sd library. Call Forget() to undo the export.
func NamedListenUnixgram ¶
NamedListenUnixgram is like ListenUnixgram, but will require any used inherited file descriptor to have the given systemd socket name The returned conn will be Export'ed by the sd library. Call Forget() to undo the export.
func Notify ¶
Notify lets you control the message sent to the nofify socket more directly. flags control whether to unset the ENV and/or to include active file descriptors in the message for systemd to store in the FDSTORE
func NotifyStatus ¶
NotifyStatus sends systemd the service status over the notify socket.
func ReplaceProcess ¶
ReplaceProcess calls StartProcess, after setting up environment variables instructing the new process to signal the process calling ReplaceProcess for termination. To enable this signaling in the child process, call SignalParentTermination when ready.
func ReplaceProcessEnv ¶
ReplaceProcessEnv - like ReplaceProcess, but allows extra environment variables to be passed into the new instance
func Reset ¶
func Reset()
Reset does a Cleanup() and makes the current Exported set of file descriptors available again as if they were inherited.
func SetUnixSocketUnlinkPolicy ¶
func SetUnixSocketUnlinkPolicy(policy uint32)
SetUnixSocketUnlinkPolicy decides how the sd library will deal with stale UNIX socket file when you create a new listening Unix socket which is not inherited from the environment the parent process (maybe systemd socket activation) made for your process.
About UNIX domain sockets: UNIX sockets don't work exactly like TCP/UDP sockets. The kernel doesn't reclaim the "address" (ie. the socket file) when the last file descriptor is closed. The file still hangs around - and will prevent a new bind(2) to that adddress/path.
Go has before version 1.7 solved this by doing unlink(2) on the file when you call Close() on a net.UnixListener. This doesn't play well with systemd socket activation though (or any graceful restart system transferring file descriptors).
Systemd doesn't expect the file to disappear and removing it will prevent clients for connecting to the listener. See: https://github.com/golang/go/issues/13877
Go 1.7 introduced some magic where listeners created with FileListener() would not do this.
Go 1.8 allow the user to control this with SetUnlinkOnClose().
The unix(7) manpage says: "Binding to a socket with a filename creates a socket in the filesystem that must be deleted by the caller when it is no longer needed".
However...
This may not be easy to guarantee... a process can crash before it removes the file. As evidence the same unix(7) man page exemplifies this with code where it calls unlink(2) just before bind(2) "In case the program exited inadvertently on the last run, remove the socket."
Always unlinking the socket file might not be the thing you want either. There might be another instance of your daemon using it. Then unlinking would "steal" the address from the other process. This might be what you want - but you would have a small window without a socket file where clients would get rejected.
So... the sd library will not try to unlink on close. In fact, it uses SetUnlinkOnClose(false) to never do this for any UNIX listener. Instead the sd library encourages "UnlinkBeforeBind". In other words: When it needs to create a new socket file it employs a UnixSocketUnlinkPolicy. This policy can be none (do not unlinK) or always unlink. Or it can be "test if the socket file is a socket file first". None of these will however "just work" in any scenario. Therefore there's a "use flock(2)" policy to use advisory file locking to ensure the socket file is only removed when there's no other process using it.
The default is UnixSocketUnlinkPolicySocket. You need to change this ( like, in you init() ) to use the flock(2) mechanism.
func SignalParentTermination ¶
func SignalParentTermination() error
SignalParentTermination signals any parent who have asked to be terminated via the ENV
func StartProcess ¶
StartProcess starts a new process passing it the open files. It starts a new process using the same environment and arguments as when it was originally started. This allows for a newly deployed binary to be started. It returns the pid of the newly started process when successful.
func WatchdogEnabled ¶
WatchdogEnabled tell whether systemd asked us to enable watchdog notifications.
Types ¶
type FileTest ¶
FileTest is a function returning whether an *os.File fulfills certain criteria. You can write these your self - and should, if the provided ones don't cover your requirements fully.
func IsListening ¶
IsListening FileTest to determine whether a file descriptor is a listening socket or not.
func IsSoReusePort ¶
func IsSoReusePort() FileTest
IsSoReusePort - Test if SO_REUSEPORT is set on the socket
func IsSocket ¶
IsSocket is similar to libsystemd sd-daemon sd_is_socket() Test whether the *os.File is a socket of family, socket type and whether it's listening. Values for "dont' care" is respectively 0, 0, and -1
func IsSocketInet ¶
IsSocketInet is similar to sd_is_socket_inet Test if the *os.File is a socket of AF_INET/AF_INET6 of the given socket time, listening (0,1,-1) and port
func IsSocketUnix ¶
IsSocketUnix is like libsystemd sd-daemon sd_is_socket_unix() path is a pointer to allow for "don't care" option by passing nil pointer. The empty string is the unnamed socket.
func IsTCPListener ¶
IsTCPListener tests whether the *os.File is a listening TCP socket. If addr != nil it's tested whether it is bound to that address.
func IsUDPListener ¶
IsUDPListener is like IsTCPListener, but for UDP
func IsUNIXListener ¶
IsUNIXListener tests if the *os.File is a unix(7) socket listening on the given address. Setting addr == nil, means "any" AF_UNIX address. Including linux abstract sockets.