feat(systemd): Support reloading

Signed-off-by: Steffen Vogel <post@steffenvogel.de>
This commit is contained in:
Steffen Vogel
2024-12-24 12:13:08 +01:00
parent c3a6b6e2bb
commit 889e4dd177
5 changed files with 75 additions and 1 deletions

View File

@@ -7,6 +7,7 @@ import (
"errors"
"fmt"
"strings"
"time"
"go.uber.org/zap"
"golang.zx2c4.com/wireguard/wgctrl"
@@ -108,7 +109,7 @@ func (d *Daemon) Start() error {
return fmt.Errorf("initial sync failed: %w", err)
}
signals := osx.SetupSignals(osx.SigUpdate)
signals := osx.SetupSignals(osx.SigUpdate, osx.SigReload)
wdt, err := d.watchdogTicker()
if err != nil && !errors.Is(err, errNotSupported) {
@@ -129,6 +130,12 @@ out:
if err := d.Sync(); err != nil {
d.logger.Error("Failed to synchronize interfaces", zap.Error(err))
}
case osx.SigReload:
if err := d.reload(); err != nil {
return err
}
default:
break out
}
@@ -276,6 +283,22 @@ func (d *Daemon) watchdogTicker() (<-chan time.Time, error) {
return time.NewTicker(wdInterval / 2).C, nil
}
func (d *Daemon) reload() error {
if err := d.setState(StateReloading); err != nil {
return fmt.Errorf("failed transition state: %w", err)
}
if _, err := d.Config.ReloadAllSources(); err != nil {
d.logger.Error("Failed to reload config", zap.Error(err))
}
if err := d.setState(StateReady); err != nil {
return fmt.Errorf("failed transition state: %w", err)
}
return nil
}
func (d *Daemon) setState(s State) error {
d.state = s
@@ -308,6 +331,18 @@ func (d *Daemon) setState(s State) error {
func (d *Daemon) notify(notify string) error {
notifyMessages := []string{notify}
if notify == systemd.NotifyReloading {
now, err := osx.GetClockMonotonic()
if err != nil {
return fmt.Errorf("failed to get monotonic clock: %w", err)
}
notifyMessages = append(notifyMessages,
fmt.Sprintf("MONOTONIC_USEC=%d", now.UnixMicro()))
d.logger.DebugV(5, "Notifying systemd", zap.Strings("message", notifyMessages))
}
if _, err := systemd.Notify(false, strings.Join(notifyMessages, "\n")); err != nil {
return err
}

22
pkg/os/clock_linux.go Normal file
View File

@@ -0,0 +1,22 @@
// SPDX-FileCopyrightText: 2023-2024 Steffen Vogel <post@steffenvogel.de>
// SPDX-License-Identifier: Apache-2.0
package os
import (
"syscall"
"time"
"unsafe"
"golang.org/x/sys/unix"
)
// GetClockMonotonic returns the current time from the CLOCK_MONOTONIC clock.
func GetClockMonotonic() (t time.Time, err error) {
var ts syscall.Timespec
if _, _, err := syscall.Syscall(syscall.SYS_CLOCK_GETTIME, unix.CLOCK_MONOTONIC, uintptr(unsafe.Pointer(&ts)), 0); err != 0 {
return time.Time{}, err
}
return time.Unix(int64(ts.Sec), int64(ts.Nsec)), nil //nolint:unconvert
}

15
pkg/os/clock_others.go Normal file
View File

@@ -0,0 +1,15 @@
// SPDX-FileCopyrightText: 2023-2024 Steffen Vogel <post@steffenvogel.de>
// SPDX-License-Identifier: Apache-2.0
//go:build !linux
package os
import (
"time"
)
// GetClockMonotonic returns the current time from the CLOCK_MONOTONIC clock.
func GetClockMonotonic() (t time.Time, err error) {
return time.Now(), nil
}

View File

@@ -11,4 +11,5 @@ import (
const (
SigUpdate = unix.SIGUSR1
SigReload = unix.SIGHUP
)

View File

@@ -11,4 +11,5 @@ import (
const (
SigUpdate = syscall.Signal(-1) // not supported
SigReload = syscall.Signal(-2) // not supported
)