Skip to content

Instantly share code, notes, and snippets.

@jn0
Created December 3, 2019 07:46
Show Gist options
  • Save jn0/21b0c8b8128f6293d3319b9413fb9e62 to your computer and use it in GitHub Desktop.
Save jn0/21b0c8b8128f6293d3319b9413fb9e62 to your computer and use it in GitHub Desktop.
Implement the sd_notify protocol to talk to systemd (Type=notify)
package main
// https://github.com/coreos/go-systemd/blob/master/daemon/sdnotify.go
import (
"net"
"os"
"fmt"
)
const (
sdNotifyEnvVar = "NOTIFY_SOCKET"
sdNotifyNet = "unixgram"
// SdNotifyReady tells the service manager that service startup is
// finished or the service finished loading its configuration.
sdNotifyReady = "READY=1"
// SdNotifyStopping tells the service manager that the service is
// beginning its shutdown.
sdNotifyStopping = "STOPPING=1"
// SdNotifyReloading tells the service manager that this service is
// reloading its configuration. Note that you must call SdNotifyReady
// when it completed reloading.
sdNotifyReloading = "RELOADING=1"
// SdNotifyWatchdog tells the service manager to update the watchdog
// timestamp for the service.
sdNotifyWatchdog = "WATCHDOG=1"
sdNotifyStatus = "STATUS=" // ...
)
type SdNotifier struct{
socketAddr *net.UnixAddr
}
func (self *SdNotifier) Available() bool {
return self != nil && self.socketAddr != nil && self.socketAddr.Name != ""
}
func (self *SdNotifier) notify(state string) (bool, error) {
if !self.Available() {
return false, nil // that's a quiet thing
}
log.Info("sd_notify(%+q)", state)
conn, err := net.DialUnix(self.socketAddr.Net, nil, self.socketAddr)
if err != nil {
log.Error("notify(%+q) dial: %v", state, err)
return false, err
}
defer conn.Close()
if _, err = conn.Write([]byte(state)); err != nil {
log.Error("notify(%+q) write: %v", state, err)
return false, err
}
return true, nil
}
func (self *SdNotifier) ImAlive() (bool, error) {
return self.notify(sdNotifyWatchdog)
}
func (self *SdNotifier) Reloading() (bool, error) {
return self.notify(sdNotifyReloading)
}
func (self *SdNotifier) Ready() (bool, error) {
return self.notify(sdNotifyReady)
}
func (self *SdNotifier) Stopping() (bool, error) {
return self.notify(sdNotifyStopping)
}
func (self *SdNotifier) Status(message string, args ...interface{}) (bool, error) {
return self.notify(sdNotifyStatus + fmt.Sprintf(message, args...))
}
func NewSdNotifier(unsetEnvironment bool) (*SdNotifier, error) {
env := os.Getenv(sdNotifyEnvVar)
if unsetEnvironment {
if err := os.Unsetenv(sdNotifyEnvVar); err != nil {
return nil, err
}
}
log.Debug("$%v=%#v", sdNotifyEnvVar, env)
if env == "" { return nil, nil; }
sdn := &SdNotifier{
socketAddr: &net.UnixAddr{
Name: env,
Net: sdNotifyNet,
},
}
return sdn, nil
}
/* EOF */
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment