From 7878bb938e4dd1b36fb6704843f1e52f189d419d Mon Sep 17 00:00:00 2001 From: "Remy D. Farley" Date: Sat, 15 Jun 2024 14:40:39 +0000 Subject: [PATCH] Add logic to notify service manager when start up is completed --- cmd/yggdrasil/main.go | 4 ++ cmd/yggdrasil/notify_startup_linux.go | 50 ++++++++++++++++++++++++ cmd/yggdrasil/notify_startup_other.go | 8 ++++ contrib/systemd/yggdrasil.service | 4 ++ contrib/systemd/yggdrasil.service.debian | 1 + 5 files changed, 67 insertions(+) create mode 100644 cmd/yggdrasil/notify_startup_linux.go create mode 100644 cmd/yggdrasil/notify_startup_other.go diff --git a/cmd/yggdrasil/main.go b/cmd/yggdrasil/main.go index 82b85cd4..dbb496d2 100644 --- a/cmd/yggdrasil/main.go +++ b/cmd/yggdrasil/main.go @@ -272,6 +272,10 @@ func main() { } } + if _, err = notifyStartupCompleted(); err != nil { + log.Warnln("Error while sending start up notification:", err) + } + // Block until we are told to shut down. <-ctx.Done() diff --git a/cmd/yggdrasil/notify_startup_linux.go b/cmd/yggdrasil/notify_startup_linux.go new file mode 100644 index 00000000..d5f090d0 --- /dev/null +++ b/cmd/yggdrasil/notify_startup_linux.go @@ -0,0 +1,50 @@ +//go:build linux +// +build linux + +package main + +import ( + "net" + "os" +) + +// Notify systemd daemon when start up is completed. +// Required to ensure that dependent services are started only after TUN interface is ready. +// +// One of the following is returned: +// (false, nil) - notification not supported (i.e. `notifySocketEnv` is unset) +// (false, err) - notification supported, but failure happened (e.g. error connecting to `notifySocketEnv` or while sending data) +// (true, nil) - notification supported, data has been sent +// +// Based on `SdNotify` from [`coreos/go-systemd`](https://github.com/coreos/go-systemd/blob/7d375ecc2b092916968b5601f74cca28a8de45dd/daemon/sdnotify.go#L56) +func notifyStartupCompleted() (bool, error) { + const ( + notifyReady = "READY=1" + notifySocketEnv = "NOTIFY_SOCKET" + ) + + socketAddr := &net.UnixAddr{ + Name: os.Getenv(notifySocketEnv), + Net: "unixgram", + } + + // `notifySocketEnv` not set + if socketAddr.Name == "" { + return false, nil + } + + os.Unsetenv(notifySocketEnv) + + conn, err := net.DialUnix(socketAddr.Net, nil, socketAddr) + // Error connecting to `notifySocketEnv` + if err != nil { + return false, err + } + defer conn.Close() + + if _, err = conn.Write([]byte(notifyReady)); err != nil { + return false, err + } + + return true, nil +} diff --git a/cmd/yggdrasil/notify_startup_other.go b/cmd/yggdrasil/notify_startup_other.go new file mode 100644 index 00000000..f3107fb6 --- /dev/null +++ b/cmd/yggdrasil/notify_startup_other.go @@ -0,0 +1,8 @@ +//go:build !linux +// +build !linux + +package main + +func notifyStartupCompleted() (bool, error) { + return false, nil +} diff --git a/contrib/systemd/yggdrasil.service b/contrib/systemd/yggdrasil.service index cdada6c0..8dbc8113 100644 --- a/contrib/systemd/yggdrasil.service +++ b/contrib/systemd/yggdrasil.service @@ -6,6 +6,10 @@ After=network-online.target After=yggdrasil-default-config.service [Service] +Type=notify +# Allow forked off processes to send notifications. +# Uncomment if e.g. yggdrasil is started by a script. +#NotifyAccess=all Group=yggdrasil ProtectHome=true ProtectSystem=true diff --git a/contrib/systemd/yggdrasil.service.debian b/contrib/systemd/yggdrasil.service.debian index 0f3c7a8d..fb298824 100644 --- a/contrib/systemd/yggdrasil.service.debian +++ b/contrib/systemd/yggdrasil.service.debian @@ -6,6 +6,7 @@ After=network-online.target After=yggdrasil-default-config.service [Service] +Type=notify Group=yggdrasil ProtectHome=true ProtectSystem=strict