summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2023-04-17 19:47:08 +0300
committerPaul Buetow <paul@buetow.org>2023-04-17 19:47:08 +0300
commitf7456fded178b85637c82255e9c3178817f5fa68 (patch)
tree78d4a0e2d03793f3a1ce5ae6a14fa7684b59b598
parente96f62acfd73d1c6b9a540927ada2ac8c81cffc1 (diff)
initial version
-rw-r--r--check.go31
-rw-r--r--config.go65
-rw-r--r--exitcodes.go21
-rw-r--r--go.mod3
-rw-r--r--gogios.json17
-rw-r--r--main.go33
-rw-r--r--notify.go28
-rw-r--r--state.go5
8 files changed, 203 insertions, 0 deletions
diff --git a/check.go b/check.go
new file mode 100644
index 0000000..b011eba
--- /dev/null
+++ b/check.go
@@ -0,0 +1,31 @@
+package main
+
+import (
+ "bytes"
+ "context"
+ "log"
+ "os/exec"
+)
+
+type check struct {
+ Name string
+ Plugin string
+ Args []string
+}
+
+func (c check) execute(ctx context.Context) (string, int) {
+ cmd := exec.CommandContext(ctx, c.Plugin, c.Args...)
+
+ var bytes bytes.Buffer
+ cmd.Stdout = &bytes
+ cmd.Stderr = &bytes
+ log.Println(ctx)
+
+ if err := cmd.Run(); err != nil {
+ if ctx.Err() == context.DeadlineExceeded {
+ return "Check command timed out", critical
+ }
+ }
+
+ return bytes.String(), cmd.ProcessState.ExitCode()
+}
diff --git a/config.go b/config.go
new file mode 100644
index 0000000..b79e275
--- /dev/null
+++ b/config.go
@@ -0,0 +1,65 @@
+package main
+
+import (
+ "encoding/json"
+ "fmt"
+ "io/ioutil"
+ "log"
+ "os"
+)
+
+type config struct {
+ EmailTo string
+ EmailFrom string
+ SMTPServer string `json:"omitempty"`
+ StateDir string `json:"omitempty"`
+ CheckTimeoutS int
+ Checks []check
+}
+
+func newConfig(configFile string) (config, error) {
+ var config config
+
+ // Open the file
+ file, err := os.Open(configFile)
+ if err != nil {
+ return config, err
+ }
+ defer file.Close()
+
+ // Read the file content
+ bytes, err := ioutil.ReadAll(file)
+ if err != nil {
+ return config, err
+ }
+
+ // Parse the JSON content
+ err = json.Unmarshal(bytes, &config)
+ if err != nil {
+ return config, err
+ }
+
+ if config.SMTPServer == "" {
+ hostname, err := os.Hostname()
+ if err != nil {
+ panic(err)
+ }
+ config.SMTPServer = fmt.Sprintf("%s:25", hostname)
+ log.Println("Set SMTPServer to " + config.SMTPServer)
+ }
+
+ if config.StateDir == "" {
+ config.StateDir = "."
+ log.Println("Set StateDir to " + config.StateDir)
+ }
+
+ dedup := make(map[string]interface{})
+ for _, check := range config.Checks {
+ if _, ok := dedup[check.Name]; ok {
+ return config, fmt.Errorf("Duplicate definition of check %s", check.Name)
+ }
+ dedup[check.Name] = struct{}{}
+ }
+
+ return config, nil
+}
diff --git a/exitcodes.go b/exitcodes.go
new file mode 100644
index 0000000..18e3e19
--- /dev/null
+++ b/exitcodes.go
@@ -0,0 +1,21 @@
+package main
+
+const (
+ ok = 0
+ warning = 1
+ critical = 2
+ unknown = 3
+)
+
+func codeToString(state int) string {
+ switch state {
+ case 0:
+ return "OK"
+ case 1:
+ return "WARNING"
+ case 2:
+ return "CRITICAL"
+ default:
+ return "UNKNOWN"
+ }
+}
diff --git a/go.mod b/go.mod
new file mode 100644
index 0000000..e8c05ec
--- /dev/null
+++ b/go.mod
@@ -0,0 +1,3 @@
+module codeberg.org/snonux/gogios
+
+go 1.19
diff --git a/gogios.json b/gogios.json
new file mode 100644
index 0000000..2f2dbe0
--- /dev/null
+++ b/gogios.json
@@ -0,0 +1,17 @@
+{
+ "EmailTo": "paul",
+ "EmailFrom": "gogios@buetow.org",
+ "CheckTimeoutS": 10,
+ "Checks": [
+ {
+ "Name": "www.foo.zone HTTP IPv4",
+ "Plugin": "/usr/local/libexec/nagios/check_http",
+ "Args": ["www.foo.zone", "-4"]
+ },
+ {
+ "Name": "www.foo.zone HTTP IPv6",
+ "Plugin": "/usr/local/libexec/nagios/check_http",
+ "Args": ["www.foo.zone", "-6"]
+ }
+ ]
+}
diff --git a/main.go b/main.go
new file mode 100644
index 0000000..cf63a5f
--- /dev/null
+++ b/main.go
@@ -0,0 +1,33 @@
+package main
+
+import (
+ "context"
+ "flag"
+ "fmt"
+ "log"
+ "time"
+)
+
+func main() {
+ log.Println("Welcome to Gogios!")
+
+ configFile := flag.String("cfg", "/etc/gogios.json", "The config file")
+
+ flag.Parse()
+
+ config, err := newConfig(*configFile)
+ if err != nil {
+ panic(err)
+ }
+
+ for _, check := range config.Checks {
+ ctx, cancel := context.WithTimeout(context.Background(),
+ time.Duration(config.CheckTimeoutS)*time.Second)
+ defer cancel()
+
+ if output, status := check.execute(ctx); status != ok {
+ subject := fmt.Sprintf("GOGIOS %s: %s", codeToString(status), check.Name)
+ notify(config, subject, output)
+ }
+ }
+}
diff --git a/notify.go b/notify.go
new file mode 100644
index 0000000..c31a242
--- /dev/null
+++ b/notify.go
@@ -0,0 +1,28 @@
+package main
+
+import (
+ "fmt"
+ "log"
+ "net/smtp"
+)
+
+func notify(config config, subject, body string) error {
+ log.Println("emailNotify", subject, body)
+
+ headers := make(map[string]string)
+ headers["From"] = config.EmailFrom
+ headers["To"] = config.EmailTo
+ headers["Subject"] = subject
+ headers["MIME-Version"] = "1.0"
+ headers["Content-Type"] = "text/plain; charset=\"utf-8\""
+
+ header := ""
+ for k, v := range headers {
+ header += fmt.Sprintf("%s: %s\r\n", k, v)
+ }
+
+ message := header + "\r\n" + body
+ log.Println("Using SMTP server", config.SMTPServer)
+ return smtp.SendMail(config.SMTPServer, nil, config.EmailFrom,
+ []string{config.EmailTo}, []byte(message))
+}
diff --git a/state.go b/state.go
new file mode 100644
index 0000000..c3c7eab
--- /dev/null
+++ b/state.go
@@ -0,0 +1,5 @@
+package main
+
+type state struct {
+ Checks map[string]int
+}