summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--README.md2
-rw-r--r--cmd/gorum/main.go2
-rw-r--r--internal/config/config.go20
-rw-r--r--internal/notifier/email.go (renamed from internal/quorum/notify.go)19
-rw-r--r--internal/notifier/notifier.go60
-rw-r--r--internal/quorum/quorum.go61
-rw-r--r--internal/run.go6
7 files changed, 102 insertions, 68 deletions
diff --git a/README.md b/README.md
index eda378c..05bccc9 100644
--- a/README.md
+++ b/README.md
@@ -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!")