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 }