Skip to content

Instantly share code, notes, and snippets.

@DavidWittman
Last active August 29, 2015 14:16
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save DavidWittman/bfb8c195b596f647abab to your computer and use it in GitHub Desktop.
Save DavidWittman/bfb8c195b596f647abab to your computer and use it in GitHub Desktop.
Status.dat parser for Icinga in Go. I'm sorry.
package main
import (
"bufio"
"bytes"
"encoding/json"
"fmt"
"os"
"strconv"
"strings"
"time"
)
// Iterates over consecutive bytes in data, beginning at the index
// start, and returning the number of characters advanced when it
// reaches a byte that is not a newline.
func skipConsecutiveNewlines(data []byte, start int) int {
var i int
for i = 0; start+i < len(data); i++ {
if data[start+i] != '\n' {
break
}
}
return i
}
// Container for the different types of checks
// Currently just HostChecks and ServiceChecks
type Checks struct {
HostChecks []*Check `json:"hostChecks"`
ServiceChecks []*Check `json:"serviceChecks"`
LastModified time.Time `json:"lastModified"`
}
// A type representing an Nagios/Icinga check
type Check struct {
Hostname string `json:"hostname"`
CurrentState uint8 `json:"currentState"`
PluginOutput string `json:"pluginOutput"`
ServiceDescription string `json:"serviceDescription"`
ProblemAcked uint8 `json:"problemAcked"`
ScheduledDowntime uint32 `json:"scheduledDowntime"`
LastStateChange uint32 `json:"lastStateChange"`
NotificationsEnabled uint8 `json:"notificationsEnabled"`
HasBeenChecked uint8 `json:"hasBeenChecked"`
CurrentAttempt uint8 `json:"currentAttempt"`
MaxAttempts uint8 `json:"maxAttempts"`
}
func toUint8(data string) uint8 {
v, err := strconv.Atoi(data)
if err != nil {
panic(err)
}
return uint8(v)
}
func toUint32(data string) uint32 {
v, err := strconv.Atoi(data)
if err != nil {
panic(err)
}
return uint32(v)
}
func NewCheck(data string) *Check {
check := new(Check)
checkData := map[string]string{
"host_name": "",
"current_state": "",
"plugin_output": "",
"service_description": "",
"problem_has_been_acknowledged": "",
"scheduled_downtime_depth": "",
"last_state_change": "",
"notifications_enabled": "",
"has_been_checked": "",
"current_attempt": "",
"max_attempts": "",
}
s := bufio.NewScanner(strings.NewReader(data))
for s.Scan() {
trimmed := strings.TrimSpace(s.Text())
result := strings.SplitN(trimmed, "=", 2)
if len(result) != 2 {
continue
}
// Check if our map has a key with this name,
// if so, set it's value the value from our input
if _, ok := checkData[result[0]]; ok {
checkData[result[0]] = result[1]
}
}
check.Hostname = checkData["host_name"]
check.PluginOutput = checkData["plugin_output"]
check.ServiceDescription = checkData["service_description"]
// NOTE(dw): This is probably the laziest marshalling ever.
check.CurrentState = toUint8(checkData["current_state"])
check.ProblemAcked = toUint8(checkData["problem_has_been_acknowledged"])
check.NotificationsEnabled = toUint8(checkData["notifications_enabled"])
check.HasBeenChecked = toUint8(checkData["has_been_checked"])
check.CurrentAttempt = toUint8(checkData["current_attempt"])
check.MaxAttempts = toUint8(checkData["max_attempts"])
check.ScheduledDowntime = toUint32(checkData["scheduled_downtime_depth"])
check.LastStateChange = toUint32(checkData["last_state_change"])
return check
}
func ScanConsecutiveLines(data []byte, atEOF bool) (advance int, token []byte, e error) {
if atEOF && len(data) == 0 {
return 0, nil, nil
}
if i := bytes.Index(data, []byte("\n\n")); i >= 0 {
skip := skipConsecutiveNewlines(data, i)
if skip > 0 {
return i + skip, data[0:i], nil
}
}
if atEOF {
return len(data), data, nil
}
// request more data
return 0, nil, nil
}
func main() {
checks := Checks{
HostChecks: make([]*Check, 0),
ServiceChecks: make([]*Check, 0),
}
tokens := [...]string{"hoststatus", "servicestatus"}
// TODO(dw): Use flags.
statusFile, err := os.Open(os.Args[1])
if err != nil {
panic(err)
}
defer statusFile.Close()
statusFileInfo, err := os.Stat(os.Args[1])
if err != nil {
panic(err)
}
checks.LastModified = statusFileInfo.ModTime()
s := bufio.NewScanner(statusFile)
s.Split(ScanConsecutiveLines)
for s.Scan() {
for _, token := range tokens {
if strings.HasPrefix(s.Text(), token) {
c := NewCheck(s.Text())
if c.CurrentState != 0 {
if token == "hoststatus" {
checks.HostChecks = append(checks.HostChecks, c)
} else if token == "servicestatus" {
checks.ServiceChecks = append(checks.ServiceChecks, c)
}
}
/*
if c.CurrentState == 2 && c.ProblemAcked == 0 && c.ScheduledDowntime == 0 && c.HasBeenChecked == 1 && c.NotificationsEnabled != 0 {
fmt.Println(c.Hostname, c.PluginOutput)
}
*/
}
}
}
checksJSON, err := json.Marshal(checks)
if err != nil {
panic(err)
}
fmt.Println(string(checksJSON))
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment