From 45fb7202ac0e606ccb7b4fe95f169424f0a6cabc Mon Sep 17 00:00:00 2001 From: Carl George Date: Mon, 5 Apr 2021 15:01:20 -0500 Subject: [PATCH] notify: Send all sd_notify signals from main caddy process (#4060) Initial sd_notify support was added in #3963, but that sent signals from both cmdRun and cmdReload. This approach has two drawbacks: - Reloads initiated via the API do not send signals. - The signals are sent from different processes, which requires the `NotifyAccess=exec` directive in the unit file. This change moves the NotifyReloading and NotifyReadiness invocations to Load, which address both of those drawbacks. It also adds a complimentary NotifyStopping method which is invoked from handleStop. All the notify methods are defined in a notify package to avoid an import loop. --- admin.go | 6 ++++++ caddy.go | 11 +++++++++++ cmd/commandfuncs.go | 13 ------------- {cmd => notify}/notify.go | 7 ++++++- {cmd => notify}/notify_linux.go | 18 +++++++++++++++--- {cmd => notify}/notify_other.go | 6 +++++- 6 files changed, 43 insertions(+), 18 deletions(-) rename {cmd => notify}/notify.go (86%) rename {cmd => notify}/notify_linux.go (79%) rename {cmd => notify}/notify_other.go (92%) diff --git a/admin.go b/admin.go index f33365750..da7ce0f58 100644 --- a/admin.go +++ b/admin.go @@ -39,6 +39,7 @@ import ( "sync" "time" + "github.com/caddyserver/caddy/v2/notify" "github.com/caddyserver/certmagic" "github.com/prometheus/client_golang/prometheus" "go.uber.org/zap" @@ -905,6 +906,11 @@ func handleStop(w http.ResponseWriter, r *http.Request) error { Err: fmt.Errorf("method not allowed"), } } + + if err := notify.NotifyStopping(); err != nil { + Log().Error("unable to notify stopping to service manager", zap.Error(err)) + } + exitProcess(Log().Named("admin.api")) return nil } diff --git a/caddy.go b/caddy.go index 46d8531f6..96dfea5c6 100644 --- a/caddy.go +++ b/caddy.go @@ -32,6 +32,7 @@ import ( "sync" "time" + "github.com/caddyserver/caddy/v2/notify" "github.com/caddyserver/certmagic" "github.com/google/uuid" "go.uber.org/zap" @@ -100,6 +101,16 @@ func Run(cfg *Config) error { // if it is different from the current config or // forceReload is true. func Load(cfgJSON []byte, forceReload bool) error { + if err := notify.NotifyReloading(); err != nil { + Log().Error("unable to notify reloading to service manager", zap.Error(err)) + } + + defer func() { + if err := notify.NotifyReadiness(); err != nil { + Log().Error("unable to notify readiness to service manager", zap.Error(err)) + } + }() + return changeConfig(http.MethodPost, "/"+rawConfigKey, cfgJSON, forceReload) } diff --git a/cmd/commandfuncs.go b/cmd/commandfuncs.go index 77d95b9a6..d32b9c763 100644 --- a/cmd/commandfuncs.go +++ b/cmd/commandfuncs.go @@ -269,10 +269,6 @@ func cmdRun(fl Flags) (int, error) { } } - if err := NotifyReadiness(); err != nil { - caddy.Log().Error("unable to notify readiness to service manager", zap.Error(err)) - } - select {} } @@ -294,15 +290,6 @@ func cmdReload(fl Flags) (int, error) { reloadCmdAddrFlag := fl.String("address") reloadCmdForceFlag := fl.Bool("force") - if err := NotifyReloading(); err != nil { - caddy.Log().Error("unable to notify reloading to service manager", zap.Error(err)) - } - defer func() { - if err := NotifyReadiness(); err != nil { - caddy.Log().Error("unable to notify readiness to service manager", zap.Error(err)) - } - }() - // get the config in caddy's native format config, configFile, err := loadConfig(reloadCmdConfigFlag, reloadCmdConfigAdapterFlag) if err != nil { diff --git a/cmd/notify.go b/notify/notify.go similarity index 86% rename from cmd/notify.go rename to notify/notify.go index 21e0e69c6..bca80c1f5 100644 --- a/cmd/notify.go +++ b/notify/notify.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package caddycmd +package notify // NotifyReadiness notifies process manager of readiness. func NotifyReadiness() error { @@ -23,3 +23,8 @@ func NotifyReadiness() error { func NotifyReloading() error { return notifyReloading() } + +// NotifyStopping notifies process manager of stopping. +func NotifyStopping() error { + return notifyStopping() +} diff --git a/cmd/notify_linux.go b/notify/notify_linux.go similarity index 79% rename from cmd/notify_linux.go rename to notify/notify_linux.go index 924c00f65..8ba49d2cd 100644 --- a/cmd/notify_linux.go +++ b/notify/notify_linux.go @@ -12,7 +12,7 @@ // See the License for the specific language governing permissions and // limitations under the License. -package caddycmd +package notify import ( "io" @@ -42,7 +42,7 @@ func sdNotify(path, payload string) error { return nil } -// notifyReadiness notifies systemd caddy that has finished its +// notifyReadiness notifies systemd that caddy has finished its // initialization routines. func notifyReadiness() error { val, ok := os.LookupEnv("NOTIFY_SOCKET") @@ -55,7 +55,7 @@ func notifyReadiness() error { return nil } -// notifyReadiness notifies systemd that caddy is reloading its config. +// notifyReloading notifies systemd that caddy is reloading its config. func notifyReloading() error { val, ok := os.LookupEnv("NOTIFY_SOCKET") if !ok || val == "" { @@ -66,3 +66,15 @@ func notifyReloading() error { } return nil } + +// notifyStopping notifies systemd that caddy is stopping. +func notifyStopping() error { + val, ok := os.LookupEnv("NOTIFY_SOCKET") + if !ok || val == "" { + return nil + } + if err := sdNotify(val, "STOPPING=1"); err != nil { + return err + } + return nil +} diff --git a/cmd/notify_other.go b/notify/notify_other.go similarity index 92% rename from cmd/notify_other.go rename to notify/notify_other.go index 4425ed773..17f62bab2 100644 --- a/cmd/notify_other.go +++ b/notify/notify_other.go @@ -14,7 +14,7 @@ // +build !linux -package caddycmd +package notify func notifyReadiness() error { return nil @@ -23,3 +23,7 @@ func notifyReadiness() error { func notifyReloading() error { return nil } + +func notifyStopping() error { + return nil +}