diff --git a/bird/bird.go b/bird/bird.go index ed33a43..2ee89b3 100644 --- a/bird/bird.go +++ b/bird/bird.go @@ -1,75 +1,75 @@ package bird import ( - "os/exec" - "strings" + "os/exec" + "strings" ) func Run(args string) ([]byte, error) { - args = "show" + args - argsList := strings.Split(args, " ") - return exec.Command("birdc", argsList...).Output() + args = "show" + args + argsList := strings.Split(args, " ") + return exec.Command("birdc", argsList...).Output() } -func RunAndParse(cmd string, parser func([]byte)(Parsed)) Parsed { - out, err := Run(cmd) +func RunAndParse(cmd string, parser func([]byte) Parsed) Parsed { + out, err := Run(cmd) - if err != nil { - // ignore errors for now - return Parsed{} - } + if err != nil { + // ignore errors for now + return Parsed{} + } - return parser(out) + return parser(out) } func Status() Parsed { - return RunAndParse("status", parseStatus) + return RunAndParse("status", parseStatus) } func Protocols() Parsed { - return RunAndParse("protocols all", parseProtocols) + return RunAndParse("protocols all", parseProtocols) } func Symbols() Parsed { - return RunAndParse("symbols", parseSymbols) + return RunAndParse("symbols", parseSymbols) } func RoutesProto(protocol string) Parsed { - return RunAndParse("route protocol " + protocol + " all", - parseRoutes) + return RunAndParse("route protocol "+protocol+" all", + parseRoutes) } func RoutesProtoCount(protocol string) Parsed { - return RunAndParse("route protocol " + protocol + " count", - parseRoutesCount) + return RunAndParse("route protocol "+protocol+" count", + parseRoutesCount) } func RoutesExport(protocol string) Parsed { - return RunAndParse("route export " + protocol + " all", - parseRoutes) + return RunAndParse("route export "+protocol+" all", + parseRoutes) } func RoutesExportCount(protocol string) Parsed { - return RunAndParse("route export " + protocol + " count", - parseRoutesCount) + return RunAndParse("route export "+protocol+" count", + parseRoutesCount) } func RoutesTable(table string) Parsed { - return RunAndParse("route table " + table + " all", - parseRoutes) + return RunAndParse("route table "+table+" all", + parseRoutes) } func RoutesTableCount(table string) Parsed { - return RunAndParse("route table " + table + " count", - parseRoutesCount) + return RunAndParse("route table "+table+" count", + parseRoutesCount) } func RoutesLookupTable(net string, table string) Parsed { - return RunAndParse("route for " + net + " table " + table + " all", - parseRoutes) + return RunAndParse("route for "+net+" table "+table+" all", + parseRoutes) } func RoutesLookupProtocol(net string, protocol string) Parsed { - return RunAndParse("route for " + net + " protocol " + protocol + " all", - parseRoutes) + return RunAndParse("route for "+net+" protocol "+protocol+" all", + parseRoutes) } diff --git a/bird/parser.go b/bird/parser.go index 4cd6a36..e2bda49 100644 --- a/bird/parser.go +++ b/bird/parser.go @@ -1,51 +1,106 @@ package bird import ( - "regexp" + "regexp" + "strconv" + "strings" ) type Parsed map[string]interface{} -func parseStatus(input []byte) Parsed { - res := Parsed{} - line_sep := regexp.MustCompile(`((\r?\n)|(\r\n?))`) - lines := line_sep.Split(string(input), -1) +func getLines(input []byte) []string { + line_sep := regexp.MustCompile(`((\r?\n)|(\r\n?))`) + lines := line_sep.Split(string(input), -1) - start_line_rx := regexp.MustCompile(`^BIRD\s([0-9\.]+)\s*$`) - router_id_rx := regexp.MustCompile(`^Router\sID\sis\s([0-9\.]+)\s*$`) - current_server_rx := regexp.MustCompile(`^Current\sserver\stime\sis\s([0-9\-]+)\s([0-9\:]+)\s*$`) - last_reboot_rx := regexp.MustCompile(`^Last\sreboot\son\s([0-9\-]+)\s([0-9\:]+)\s*$`) - last_reconfig_rx := regexp.MustCompile(`^Last\sreconfiguration\son\s([0-9\-]+)\s([0-9\:]+)\s*$`) - for _, line := range lines { - if (start_line_rx.MatchString(line)) { - res["version"] = start_line_rx.FindStringSubmatch(line)[1] - } else if (router_id_rx.MatchString(line)) { - res["router_id"] = router_id_rx.FindStringSubmatch(line)[1] - } else if (current_server_rx.MatchString(line)) { - res["current_server"] = current_server_rx.FindStringSubmatch(line)[1] - } else if (last_reboot_rx.MatchString(line)) { - res["last_reboot"] = last_reboot_rx.FindStringSubmatch(line)[1] - } else if (last_reconfig_rx.MatchString(line)) { - res["last_reconfig"] = last_reconfig_rx.FindStringSubmatch(line)[1] - } else { - res["message"] = line - } - } - return res + var filtered []string + + for _, line := range lines { + if len(strings.TrimSpace(line)) > 0 { + filtered = append(filtered, line) + } + } + + return filtered +} + +func specialLine(line string) bool { + return (strings.HasPrefix(line, "BIRD") || + strings.HasPrefix(line, "Access restricted")) +} + +func parseStatus(input []byte) Parsed { + res := Parsed{} + lines := getLines(input) + + start_line_rx := regexp.MustCompile(`^BIRD\s([0-9\.]+)\s*$`) + router_id_rx := regexp.MustCompile(`^Router\sID\sis\s([0-9\.]+)\s*$`) + current_server_rx := regexp.MustCompile(`^Current\sserver\stime\sis\s([0-9\-]+)\s([0-9\:]+)\s*$`) + last_reboot_rx := regexp.MustCompile(`^Last\sreboot\son\s([0-9\-]+)\s([0-9\:]+)\s*$`) + last_reconfig_rx := regexp.MustCompile(`^Last\sreconfiguration\son\s([0-9\-]+)\s([0-9\:]+)\s*$`) + for _, line := range lines { + if start_line_rx.MatchString(line) { + res["version"] = start_line_rx.FindStringSubmatch(line)[1] + } else if router_id_rx.MatchString(line) { + res["router_id"] = router_id_rx.FindStringSubmatch(line)[1] + } else if current_server_rx.MatchString(line) { + res["current_server"] = current_server_rx.FindStringSubmatch(line)[1] + } else if last_reboot_rx.MatchString(line) { + res["last_reboot"] = last_reboot_rx.FindStringSubmatch(line)[1] + } else if last_reconfig_rx.MatchString(line) { + res["last_reconfig"] = last_reconfig_rx.FindStringSubmatch(line)[1] + } else { + res["message"] = line + } + } + return res } func parseProtocols(input []byte) Parsed { - return Parsed{} + return Parsed{} } func parseSymbols(input []byte) Parsed { - return Parsed{} + res := Parsed{} + lines := getLines(input) + + key_rx := regexp.MustCompile(`^([^\s]+)\s+(.+)\s*$`) + for _, line := range lines { + if specialLine(line) { + continue + } + + if key_rx.MatchString(line) { + groups := key_rx.FindStringSubmatch(line) + res[groups[2]] = groups[1] + } + } + + return res } func parseRoutes(input []byte) Parsed { - return Parsed{} + return Parsed{} } func parseRoutesCount(input []byte) Parsed { - return Parsed{} + res := Parsed{} + lines := getLines(input) + + count_rx := regexp.MustCompile(`^(\d+)\s+of\s+(\d+)\s+routes.*$`) + for _, line := range lines { + if specialLine(line) { + continue + } + + if count_rx.MatchString(line) { + i, err := strconv.ParseInt(count_rx.FindStringSubmatch(line)[1], 10, 64) + if err != nil { + // ignore for now + continue + } + res["routes"] = i + } + } + + return res }