178 lines
4.9 KiB
Go
178 lines
4.9 KiB
Go
![]() |
package daemon
|
||
|
|
||
|
import (
|
||
|
`bytes`
|
||
|
`os`
|
||
|
`time`
|
||
|
|
||
|
sysd "github.com/coreos/go-systemd/daemon"
|
||
|
`github.com/davecgh/go-spew/spew`
|
||
|
`r00t2.io/gobroke/conf`
|
||
|
`r00t2.io/gobroke/runner`
|
||
|
`r00t2.io/goutils/multierr`
|
||
|
)
|
||
|
|
||
|
// Start starts an Updater. This blocks.
|
||
|
func (u *Updater) Start() (err error) {
|
||
|
|
||
|
var sig os.Signal
|
||
|
var t time.Time
|
||
|
var tunResults []*runner.TunnelResult
|
||
|
var tunsChanged bool
|
||
|
var tunsUpdated bool
|
||
|
var mErr *multierr.MultiError = multierr.NewMultiError(nil)
|
||
|
|
||
|
u.log.Debug("daemon.Updater.Start: Starting persistent Updater.")
|
||
|
|
||
|
u.timer.Reset(u.cfg.Freq)
|
||
|
|
||
|
if isSystemd {
|
||
|
var supported bool
|
||
|
|
||
|
// https://www.freedesktop.org/software/systemd/man/sd_notify.html
|
||
|
if supported, err = sysd.SdNotify(false, sysd.SdNotifyReady); err != nil {
|
||
|
u.log.Err(
|
||
|
"daemon.Updater.Start: Error encountered when notifying systemd of changestate to READY (supported: %v): %v",
|
||
|
supported, err,
|
||
|
)
|
||
|
err = nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
breakLoop:
|
||
|
for !u.isStopping {
|
||
|
if u.isStopping {
|
||
|
break
|
||
|
}
|
||
|
select {
|
||
|
case t = <-u.timer.C:
|
||
|
u.log.Debug("daemon.Updater.Start: Tick at %s; running check/update.", t.String())
|
||
|
if tunResults, tunsChanged, tunsUpdated, err = runner.Run(u.cfg, u.log); err != nil {
|
||
|
u.log.Err("daemon.Updater.Start: Received error running check/update: %v", err)
|
||
|
mErr.AddError(err)
|
||
|
err = nil
|
||
|
} else {
|
||
|
u.log.Debug(
|
||
|
"daemon.Updater.Start: Check/update finished at %s; waiting %s. Changed: %v, Updated: %v, Results:\n%s",
|
||
|
t.String(), u.cfg.Freq.String(), tunsChanged, tunsUpdated, spew.Sdump(tunResults),
|
||
|
)
|
||
|
}
|
||
|
u.timer.Reset(u.cfg.Freq)
|
||
|
case sig = <-u.reloadChan:
|
||
|
u.log.Debug("daemon.Updater.Start: Received reload signal %v (%#v): %v", sig, sig, sig.String())
|
||
|
if u.isStopping {
|
||
|
break breakLoop
|
||
|
}
|
||
|
if err = u.Reload(); err != nil {
|
||
|
u.log.Err("daemon.Updater.Start: Received error running reload: %v", err)
|
||
|
mErr.AddError(err)
|
||
|
err = nil
|
||
|
}
|
||
|
case sig = <-u.stopChan:
|
||
|
u.isStopping = true
|
||
|
u.log.Debug("daemon.Updater.Start: Received stop signal %v (%#v): %v", sig, sig, sig.String())
|
||
|
if err = u.Stop(); err != nil {
|
||
|
u.log.Err("daemon.Updater.Start: Received error stopping: %v", err)
|
||
|
mErr.AddError(err)
|
||
|
err = nil
|
||
|
}
|
||
|
break breakLoop
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if !mErr.IsEmpty() {
|
||
|
err = mErr
|
||
|
return
|
||
|
}
|
||
|
|
||
|
u.log.Debug("daemon.Updater.Start: Persistent updater stopped.")
|
||
|
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Stop stops an Updater. This is called by signal handlers in Start, and will close Start's block.
|
||
|
func (u *Updater) Stop() (err error) {
|
||
|
|
||
|
u.log.Debug("daemon.Updater.Stop: Stopping persistent Updater.")
|
||
|
|
||
|
if isSystemd {
|
||
|
// https://www.freedesktop.org/software/systemd/man/sd_notify.html
|
||
|
if _, err = sysd.SdNotify(false, sysd.SdNotifyStopping); err != nil {
|
||
|
u.log.Err("daemon.Updater.Stop: Received error notifying systemd of stop: %v", err)
|
||
|
err = nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
u.isStopping = true
|
||
|
u.timer.Stop()
|
||
|
close(u.stopChan)
|
||
|
close(u.reloadChan)
|
||
|
|
||
|
u.log.Debug("daemon.Updater.Stop: Stopped persistent Updater.")
|
||
|
|
||
|
return
|
||
|
}
|
||
|
|
||
|
// Reload reloads the configuration if it was originally set via a file.
|
||
|
func (u *Updater) Reload() (err error) {
|
||
|
|
||
|
var prevCfg *conf.Config
|
||
|
var supported bool
|
||
|
var newCksum []byte
|
||
|
|
||
|
u.log.Debug("daemon.Updater.Reload: Reloading persistent Updater.")
|
||
|
|
||
|
if isSystemd {
|
||
|
// https://www.freedesktop.org/software/systemd/man/sd_notify.html
|
||
|
if _, err = sysd.SdNotify(false, sysd.SdNotifyReloading); err != nil {
|
||
|
u.log.Err("daemon.Updater.Reload: Received error notifying systemd of reload: %v", err)
|
||
|
err = nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if u.cfg.Path() != "" {
|
||
|
if newCksum, err = conf.ChecksumPath(u.cfg.Path()); err != nil {
|
||
|
u.log.Err(
|
||
|
"daemon.Updater.Reload: Received error getting checksum of defined conf path '%s'; skipping reload: %v",
|
||
|
u.cfg.Path(), err,
|
||
|
)
|
||
|
err = nil
|
||
|
} else {
|
||
|
if bytes.Equal(newCksum, u.cfg.Checksum()) {
|
||
|
u.log.Warning("daemon.Updater.Reload: Config path '%s' checksum unchanged; skipping reload", u.cfg.Path())
|
||
|
} else {
|
||
|
prevCfg = new(conf.Config)
|
||
|
*prevCfg = *u.cfg
|
||
|
if u.cfg, err = conf.NewConfig(u.cfg.Path(), u.cfg.IsDebug(), u.log); err != nil {
|
||
|
u.log.Err("daemon.Updater.Reload: Received error parsing new config; reverting to previous configuration: %v", err)
|
||
|
err = nil
|
||
|
u.cfg = prevCfg
|
||
|
} else {
|
||
|
u.log.Debug(
|
||
|
"daemon.Updater.Reload: New configuration loaded from '%s'; restarting timer for '%s'.",
|
||
|
u.cfg.Path(), u.cfg.Freq.String(),
|
||
|
)
|
||
|
u.timer.Reset(u.cfg.Freq)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
} else {
|
||
|
u.log.Debug("daemon.Updater.Reload: No config filepath specified; NO-OP.")
|
||
|
}
|
||
|
|
||
|
if isSystemd {
|
||
|
// https://www.freedesktop.org/software/systemd/man/sd_notify.html
|
||
|
if supported, err = sysd.SdNotify(false, sysd.SdNotifyReady); err != nil {
|
||
|
u.log.Err(
|
||
|
"daemon.Updater.Reload: Error encountered when notifying systemd of changestate to READY (supported: %v): %v",
|
||
|
supported, err,
|
||
|
)
|
||
|
err = nil
|
||
|
}
|
||
|
}
|
||
|
|
||
|
u.log.Debug("daemon.Updater.Reload: Finished Updater reload.")
|
||
|
|
||
|
return
|
||
|
}
|