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.
This commit is contained in:
Carl George 2021-04-05 15:01:20 -05:00 committed by GitHub
parent 66783eb4d9
commit 45fb7202ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 43 additions and 18 deletions

View File

@ -39,6 +39,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/caddyserver/caddy/v2/notify"
"github.com/caddyserver/certmagic" "github.com/caddyserver/certmagic"
"github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus"
"go.uber.org/zap" "go.uber.org/zap"
@ -905,6 +906,11 @@ func handleStop(w http.ResponseWriter, r *http.Request) error {
Err: fmt.Errorf("method not allowed"), 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")) exitProcess(Log().Named("admin.api"))
return nil return nil
} }

View File

@ -32,6 +32,7 @@ import (
"sync" "sync"
"time" "time"
"github.com/caddyserver/caddy/v2/notify"
"github.com/caddyserver/certmagic" "github.com/caddyserver/certmagic"
"github.com/google/uuid" "github.com/google/uuid"
"go.uber.org/zap" "go.uber.org/zap"
@ -100,6 +101,16 @@ func Run(cfg *Config) error {
// if it is different from the current config or // if it is different from the current config or
// forceReload is true. // forceReload is true.
func Load(cfgJSON []byte, forceReload bool) error { 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) return changeConfig(http.MethodPost, "/"+rawConfigKey, cfgJSON, forceReload)
} }

View File

@ -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 {} select {}
} }
@ -294,15 +290,6 @@ func cmdReload(fl Flags) (int, error) {
reloadCmdAddrFlag := fl.String("address") reloadCmdAddrFlag := fl.String("address")
reloadCmdForceFlag := fl.Bool("force") 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 // get the config in caddy's native format
config, configFile, err := loadConfig(reloadCmdConfigFlag, reloadCmdConfigAdapterFlag) config, configFile, err := loadConfig(reloadCmdConfigFlag, reloadCmdConfigAdapterFlag)
if err != nil { if err != nil {

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package caddycmd package notify
// NotifyReadiness notifies process manager of readiness. // NotifyReadiness notifies process manager of readiness.
func NotifyReadiness() error { func NotifyReadiness() error {
@ -23,3 +23,8 @@ func NotifyReadiness() error {
func NotifyReloading() error { func NotifyReloading() error {
return notifyReloading() return notifyReloading()
} }
// NotifyStopping notifies process manager of stopping.
func NotifyStopping() error {
return notifyStopping()
}

View File

@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and // See the License for the specific language governing permissions and
// limitations under the License. // limitations under the License.
package caddycmd package notify
import ( import (
"io" "io"
@ -42,7 +42,7 @@ func sdNotify(path, payload string) error {
return nil return nil
} }
// notifyReadiness notifies systemd caddy that has finished its // notifyReadiness notifies systemd that caddy has finished its
// initialization routines. // initialization routines.
func notifyReadiness() error { func notifyReadiness() error {
val, ok := os.LookupEnv("NOTIFY_SOCKET") val, ok := os.LookupEnv("NOTIFY_SOCKET")
@ -55,7 +55,7 @@ func notifyReadiness() error {
return nil return nil
} }
// notifyReadiness notifies systemd that caddy is reloading its config. // notifyReloading notifies systemd that caddy is reloading its config.
func notifyReloading() error { func notifyReloading() error {
val, ok := os.LookupEnv("NOTIFY_SOCKET") val, ok := os.LookupEnv("NOTIFY_SOCKET")
if !ok || val == "" { if !ok || val == "" {
@ -66,3 +66,15 @@ func notifyReloading() error {
} }
return nil 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
}

View File

@ -14,7 +14,7 @@
// +build !linux // +build !linux
package caddycmd package notify
func notifyReadiness() error { func notifyReadiness() error {
return nil return nil
@ -23,3 +23,7 @@ func notifyReadiness() error {
func notifyReloading() error { func notifyReloading() error {
return nil return nil
} }
func notifyStopping() error {
return nil
}