diff options
| author | Paul Buetow <paul@buetow.org> | 2023-11-07 23:16:57 +0200 |
|---|---|---|
| committer | Paul Buetow <paul@buetow.org> | 2023-11-07 23:16:57 +0200 |
| commit | 50326b808865ed27df587a2b49a012c0339fb998 (patch) | |
| tree | d3bc89c22d88256555926adf9b01aad826214cc9 | |
| parent | 314aa39afda105969567c4f95b07147f372fcf98 (diff) | |
add notifier package
| -rw-r--r-- | README.md | 2 | ||||
| -rw-r--r-- | cmd/gorum/main.go | 2 | ||||
| -rw-r--r-- | internal/config/config.go | 20 | ||||
| -rw-r--r-- | internal/notifier/email.go (renamed from internal/quorum/notify.go) | 19 | ||||
| -rw-r--r-- | internal/notifier/notifier.go | 60 | ||||
| -rw-r--r-- | internal/quorum/quorum.go | 61 | ||||
| -rw-r--r-- | internal/run.go | 6 |
7 files changed, 102 insertions, 68 deletions
@@ -7,6 +7,6 @@ This project is still under development! ## TODO * Finish this TODO -* Add `notify.go` from Gogios, to notify on state changes. +* Use this to control remote Gorum check execution * Release Gorum * Write a blog post diff --git a/cmd/gorum/main.go b/cmd/gorum/main.go index 80827e9..9cb74c7 100644 --- a/cmd/gorum/main.go +++ b/cmd/gorum/main.go @@ -11,7 +11,7 @@ import ( "codeberg.org/snonux/gorum/internal" ) -const versionStr = "v0.0.3" +const versionStr = "v0.0.4" func main() { configFile := flag.String("cfg", "/etc/gorum.json", "The config file") diff --git a/internal/config/config.go b/internal/config/config.go index 3968268..2753ac9 100644 --- a/internal/config/config.go +++ b/internal/config/config.go @@ -35,6 +35,7 @@ type Config struct { EmailTo string `json:"EmailTo,omitempty"` EmailFrom string `json:"EmailFrom,omitempty"` SMTPServer string `json:"SMTPServer,omitempty"` + MailThrottle int `json:"MailThrottle,omitempty"` } func NewFromConfigFile(configFile string) (Config, error) { @@ -69,6 +70,21 @@ func NewFromConfigFile(configFile string) (Config, error) { } conf.Nodes = newNodes + if conf.SMTPServer == "" { + hostname, err := os.Hostname() + if err != nil { + log.Fatal(err) + } + conf.SMTPServer = fmt.Sprintf("%s:25", hostname) + log.Println("Set SMTPServer to " + conf.SMTPServer) + } + + if conf.MailThrottle == 0 { + // By default, send out an E-Mail once every minute max. This + // is to avoid E-Mail bursts. + conf.MailThrottle = 60 + } + return conf.setDefaults() } @@ -188,3 +204,7 @@ func (conf Config) findNode(hostname string) (Node, error) { return Node{}, fmt.Errorf("node %s not found in %v", hostname, conf.Nodes) } + +func (conf Config) EmailNotifycationEnabled() bool { + return conf.EmailFrom != "" && conf.EmailTo != "" && conf.SMTPServer != "" +} diff --git a/internal/quorum/notify.go b/internal/notifier/email.go index 7761b4d..4ce8d69 100644 --- a/internal/quorum/notify.go +++ b/internal/notifier/email.go @@ -1,4 +1,4 @@ -package quorum +package notifier import ( "fmt" @@ -8,15 +8,10 @@ import ( "codeberg.org/snonux/gorum/internal/config" ) -func notifyEnabled(conf config.Config) bool { - return conf.EmailFrom != "" && conf.EmailTo != "" && conf.SMTPServer != "" -} - -func notify(conf config.Config, subject, body string) error { - if !notifyEnabled(conf) { +func emailNotify(conf config.Config, subject, body string) error { + if !conf.EmailNotifycationEnabled() { return nil } - log.Println("notify:", subject, body) headers := map[string]string{ @@ -39,10 +34,8 @@ func notify(conf config.Config, subject, body string) error { []string{conf.EmailTo}, []byte(message)) } -func notifyError(conf config.Config, err error) { - if notifyEnabled(conf) { - if err := notify(conf, fmt.Sprintf("GORUM: An error occured: %v", err), err.Error()); err != nil { - log.Println("error:", err) - } +func emailNotifyError(conf config.Config, err error) { + if err := emailNotify(conf, fmt.Sprintf("GORUM: An error occured: %v", err), err.Error()); err != nil { + log.Println("error:", err) } } diff --git a/internal/notifier/notifier.go b/internal/notifier/notifier.go new file mode 100644 index 0000000..24447a9 --- /dev/null +++ b/internal/notifier/notifier.go @@ -0,0 +1,60 @@ +package notifier + +import ( + "context" + "fmt" + "os" + + "codeberg.org/snonux/gorum/internal/config" +) + +type Notifier struct{} + +func New() Notifier { + return Notifier{} +} + +func (notifier Notifier) Start(ctx context.Context, conf config.Config, scoreCh <-chan string) { + go func() { + for scoresStr := range scoreCh { + if err := notifier.persist(conf, scoresStr); err != nil { + emailNotifyError(conf, err) + } + } + }() +} + +func (notifier Notifier) persist(conf config.Config, scoresStr string) error { + if err := emailNotify(conf, "GORUM: Quorum changed", scoresStr); err != nil { + return err + } + + if _, err := os.Stat(conf.StateDir); os.IsNotExist(err) { + if err := os.MkdirAll(conf.StateDir, 0755); err != nil { + return err + } + } + + return writeFileViaTmp(fmt.Sprintf("%s/%s", conf.StateDir, conf.ScoreFile), scoresStr) +} + +// Create tmp file first, and then, once written, rename it. +func writeFileViaTmp(filePath, content string) error { + tmpFilePath := fmt.Sprintf("%s.tmp", filePath) + + fd, err := os.Create(tmpFilePath) + if err != nil { + return err + } + defer fd.Close() + + if _, err := fd.WriteString(content); err != nil { + return err + } + + if err := fd.Sync(); err != nil { + return err + } + + return os.Rename(tmpFilePath, filePath) +} diff --git a/internal/quorum/quorum.go b/internal/quorum/quorum.go index 71954f4..d730fed 100644 --- a/internal/quorum/quorum.go +++ b/internal/quorum/quorum.go @@ -2,9 +2,7 @@ package quorum import ( "context" - "fmt" "log" - "os" "sort" "strconv" "strings" @@ -32,8 +30,9 @@ func New(conf config.Config) Quorum { } } -func (quo Quorum) Start(ctx context.Context) <-chan vote.Vote { - ch := make(chan vote.Vote) +func (quo Quorum) Start(ctx context.Context) (<-chan vote.Vote, <-chan string) { + voteCh := make(chan vote.Vote) + scoreCh := make(chan string) interval := time.Second * time.Duration(quo.conf.LoopIntervalS) if vote.Expiry <= interval { @@ -42,7 +41,8 @@ func (quo Quorum) Start(ctx context.Context) <-chan vote.Vote { } go func() { - defer close(ch) + defer close(voteCh) + defer close(scoreCh) var ( myVote vote.Vote @@ -54,25 +54,21 @@ func (quo Quorum) Start(ctx context.Context) <-chan vote.Vote { case <-time.After(interval): myVote, _ = quo.makeMyVote() log.Println("quorum: made my vote:", myVote) - ch <- myVote + voteCh <- myVote case v := <-quo.voteCh: quo.vote(v) if myVote, changed = quo.makeMyVote(); changed { log.Println("quorum: changed my vote:", myVote) - ch <- myVote + voteCh <- myVote + scoreCh <- quo.strs() } case <-ctx.Done(): return } - - if err := quo.persist(changed); err != nil { - log.Println("quorum:", err) - notifyError(quo.conf, err) - } } }() - return ch + return voteCh, scoreCh } func (quo Quorum) Vote(v vote.Vote) { @@ -149,24 +145,6 @@ func (quo *Quorum) strs() string { return sb.String() } -func (quo *Quorum) persist(changed bool) error { - scoresStr := quo.strs() - - if changed { - if err := notify(quo.conf, "GORUM: Quorum changed", scoresStr); err != nil { - return err - } - } - - if _, err := os.Stat(quo.conf.StateDir); os.IsNotExist(err) { - if err := os.MkdirAll(quo.conf.StateDir, 0755); err != nil { - return err - } - } - - return writeFileViaTmp(fmt.Sprintf("%s/%s", quo.conf.StateDir, quo.conf.ScoreFile), scoresStr) -} - func (quo *Quorum) makeMyVote() (vote.Vote, bool) { newVote, err := quo.expireOldVotes() if err != nil { @@ -201,24 +179,3 @@ func (quo Quorum) expireOldVotes() (vote.Vote, error) { return vote.New(quo.conf, live...) } - -// Create tmp file first, and then, once written, rename it. -func writeFileViaTmp(filePath, content string) error { - tmpFilePath := fmt.Sprintf("%s.tmp", filePath) - - fd, err := os.Create(tmpFilePath) - if err != nil { - return err - } - defer fd.Close() - - if _, err := fd.WriteString(content); err != nil { - return err - } - - if err := fd.Sync(); err != nil { - return err - } - - return os.Rename(tmpFilePath, filePath) -} diff --git a/internal/run.go b/internal/run.go index 2439928..d07ba28 100644 --- a/internal/run.go +++ b/internal/run.go @@ -7,6 +7,7 @@ import ( "codeberg.org/snonux/gorum/internal/client" "codeberg.org/snonux/gorum/internal/config" + "codeberg.org/snonux/gorum/internal/notifier" "codeberg.org/snonux/gorum/internal/quorum" "codeberg.org/snonux/gorum/internal/server" ) @@ -32,9 +33,12 @@ func Run(ctx context.Context, configFile string, loopIntervalS int64) error { log.Println("Starting everything up!") quo := quorum.New(conf) - myVoteCh := quo.Start(ctx) + notifier := notifier.New() + + myVoteCh, scoreCh := quo.Start(ctx) server.Start(ctx, conf, quo) client.Start(ctx, conf, myVoteCh) + notifier.Start(ctx, conf, scoreCh) <-ctx.Done() log.Println("Good bye and have a nice day!") |
