Last active
August 29, 2015 14:16
-
-
Save DavidWittman/bfb8c195b596f647abab to your computer and use it in GitHub Desktop.
Status.dat parser for Icinga in Go. I'm sorry.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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