mirror of
https://github.com/alice-lg/birdwatcher.git
synced 2025-03-09 00:00:05 +01:00
refactored endpoints
This commit is contained in:
parent
ce63916596
commit
fc0ea09dc3
15 changed files with 127 additions and 3032 deletions
|
@ -42,7 +42,7 @@ func ProtocolsBgp() Parsed {
|
|||
}
|
||||
}
|
||||
|
||||
return bgpProto
|
||||
return Parsed{"protocols": bgpProto}
|
||||
}
|
||||
|
||||
func Symbols() Parsed {
|
||||
|
|
135
birdwatcher.go
135
birdwatcher.go
|
@ -2,128 +2,39 @@ package main
|
|||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"log"
|
||||
"log/syslog"
|
||||
"net/http"
|
||||
"os"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/julienschmidt/httprouter"
|
||||
yaml "gopkg.in/yaml.v2"
|
||||
"github.com/mchackorg/birdwatcher/endpoints"
|
||||
)
|
||||
|
||||
var debug int = 0
|
||||
var slog *syslog.Writer // Our syslog connection
|
||||
var conf *Config
|
||||
|
||||
type Match struct {
|
||||
Expr string // The regular expression as a string.
|
||||
Fields []string // The named fields for grouped expressions.
|
||||
Next string // The next regular expression in the flow.
|
||||
Action string // What to do with the stored fields: "store" or "send".
|
||||
}
|
||||
|
||||
// Compiled regular expression and it's corresponding match data.
|
||||
type RE struct {
|
||||
RE *regexp.Regexp
|
||||
Match Match
|
||||
}
|
||||
|
||||
// The configuration found in the configuration file.
|
||||
type FileConfig struct {
|
||||
Matches map[string]Match // All our regular expressions and related data.
|
||||
Listen string // Listen to this address:port for HTTP.
|
||||
FileName string // File to look for patterns
|
||||
|
||||
}
|
||||
|
||||
type Config struct {
|
||||
Conf FileConfig
|
||||
Res map[string]RE
|
||||
}
|
||||
|
||||
// Parse the configuration file. Returns the configuration.
|
||||
func parseconfig(filename string) (conf *Config, err error) {
|
||||
conf = new(Config)
|
||||
|
||||
contents, err := ioutil.ReadFile(filename)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
if err = yaml.Unmarshal(contents, &conf.Conf); err != nil {
|
||||
return
|
||||
}
|
||||
|
||||
conf.Res = make(map[string]RE)
|
||||
|
||||
// Build the regexps from the configuration.
|
||||
for key, match := range conf.Conf.Matches {
|
||||
var err error
|
||||
var re RE
|
||||
|
||||
re.Match = match
|
||||
re.RE, err = regexp.Compile(match.Expr)
|
||||
if err != nil {
|
||||
slog.Err("Couldn't compile re: " + match.Expr)
|
||||
os.Exit(-1)
|
||||
}
|
||||
|
||||
// Check that the number of capturing groups matches the number of expected fields.
|
||||
lengroups := len(re.RE.SubexpNames()) - 1
|
||||
lenfields := len(re.Match.Fields)
|
||||
|
||||
if lengroups != lenfields {
|
||||
line := fmt.Sprintf("Number of capturing groups (%v) not equal to number of fields (%v): %s", lengroups, lenfields, re.Match.Expr)
|
||||
slog.Err(line)
|
||||
os.Exit(-1)
|
||||
}
|
||||
|
||||
conf.Res[key] = re
|
||||
}
|
||||
|
||||
return
|
||||
func makeRouter() *httprouter.Router {
|
||||
r := httprouter.New()
|
||||
r.GET("/status", endpoints.Endpoint(endpoints.Status))
|
||||
r.GET("/protocols/bgp", endpoints.Endpoint(endpoints.Bgp))
|
||||
r.GET("/symbols", endpoints.Endpoint(endpoints.Symbols))
|
||||
r.GET("/symbols/tables", endpoints.Endpoint(endpoints.SymbolTables))
|
||||
r.GET("/symbols/protocols", endpoints.Endpoint(endpoints.SymbolProtocols))
|
||||
r.GET("/routes/protocol/:protocol", endpoints.Endpoint(endpoints.ProtoRoutes))
|
||||
r.GET("/routes/table/:table", endpoints.Endpoint(endpoints.TableRoutes))
|
||||
r.GET("/routes/count/protocol/:protocol", endpoints.Endpoint(endpoints.ProtoCount))
|
||||
r.GET("/routes/count/table/:table", endpoints.Endpoint(endpoints.TableCount))
|
||||
r.GET("/route/net/:net", endpoints.Endpoint(endpoints.RouteNet))
|
||||
r.GET("/route/net/:net/table/:table", endpoints.Endpoint(endpoints.RouteNetTable))
|
||||
r.GET("/protocols", endpoints.Endpoint(endpoints.Protocols))
|
||||
return r
|
||||
}
|
||||
|
||||
func main() {
|
||||
var configfile = flag.String("config", "birdwatcher.yaml", "Path to configuration file")
|
||||
var flagdebug = flag.Int("debug", 0, "Be more verbose")
|
||||
port := flag.String("port",
|
||||
"29184",
|
||||
"The port the birdwatcher should run on")
|
||||
flag.Parse()
|
||||
|
||||
debug = *flagdebug
|
||||
r := makeRouter()
|
||||
|
||||
slog, err := syslog.New(syslog.LOG_ERR, "birdwatcher")
|
||||
if err != nil {
|
||||
fmt.Printf("Couldn't open syslog")
|
||||
os.Exit(-1)
|
||||
}
|
||||
|
||||
slog.Debug("birdwatcher starting")
|
||||
|
||||
config, err := parseconfig(*configfile)
|
||||
if err != nil {
|
||||
slog.Err("Couldn't parse configuration file: " + err.Error())
|
||||
os.Exit(-1)
|
||||
}
|
||||
conf = config
|
||||
|
||||
fmt.Printf("%v\n", conf)
|
||||
|
||||
r := httprouter.New()
|
||||
r.GET("/status", Status) // done
|
||||
r.GET("/protocols/bgp", Bgp)
|
||||
r.GET("/symbols", Symbols) // done
|
||||
r.GET("/symbols/tables", SymbolTables) //done
|
||||
r.GET("/symbols/protocols", SymbolProtocols) // done
|
||||
r.GET("/routes/protocol/:protocol", ProtoRoutes) //done
|
||||
r.GET("/routes/table/:table", TableRoutes) //done
|
||||
r.GET("/routes/count/protocol/:protocol", ProtoCount) //done
|
||||
r.GET("/routes/count/table/:table", TableCount) // done
|
||||
r.GET("/route/net/:net", RouteNet) // done
|
||||
r.GET("/route/net/:net/table/:table", RouteNetTable) // done
|
||||
r.GET("/protocols", Protocols) // done
|
||||
|
||||
log.Fatal(http.ListenAndServe(":29184", r))
|
||||
realPort :=strings.Join([]string{":", *port}, "")
|
||||
log.Fatal(http.ListenAndServe(realPort, r))
|
||||
}
|
||||
|
|
|
@ -1,31 +0,0 @@
|
|||
---
|
||||
filename: v4-show-protocols-all.txt
|
||||
|
||||
# A map of all the expected patterns.
|
||||
# fields: A list of variables to set from the grouped patterns.
|
||||
# expr: The regular expression.
|
||||
# next: The next regexp to go to after the current one has a match. ""
|
||||
# if we are finished.
|
||||
# action: What to do with the stored values.
|
||||
|
||||
matches:
|
||||
|
||||
# pp_0236_as10310 Pipe master up 2016-07-22 => t_0236_as10310
|
||||
getprotocol:
|
||||
fields:
|
||||
- protocol
|
||||
- table
|
||||
- state
|
||||
- state_changed
|
||||
- connection
|
||||
expr: '^(\w+)\s+BGP\s+(\w+)\s+(\w+)\s+([0-9\-]+)\s+(\w+)\s*$'
|
||||
next: "protdescription"
|
||||
action: store
|
||||
|
||||
# Description: Pipe for AS10310 - Yahoo! - VLAN Interface 236
|
||||
protdescription:
|
||||
fields:
|
||||
- description
|
||||
expr: " Description: (.*)"
|
||||
next: "getprotocol" # back again for more similar lines
|
||||
action: send # Done here, send it back.
|
30
endpoints/endpoint.go
Normal file
30
endpoints/endpoint.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
package endpoints
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/julienschmidt/httprouter"
|
||||
"github.com/mchackorg/birdwatcher/bird"
|
||||
)
|
||||
|
||||
func Endpoint(wrapped func(httprouter.Params) (bird.Parsed)) httprouter.Handle {
|
||||
return func(w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
ps httprouter.Params) {
|
||||
res := make(map[string]interface{})
|
||||
|
||||
res["api"] = GetApiInfo()
|
||||
|
||||
ret := wrapped(ps)
|
||||
|
||||
for k, v := range ret {
|
||||
res[k] = v
|
||||
}
|
||||
|
||||
js, _ := json.Marshal(res)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(js)
|
||||
}
|
||||
}
|
14
endpoints/protocols.go
Normal file
14
endpoints/protocols.go
Normal file
|
@ -0,0 +1,14 @@
|
|||
package endpoints
|
||||
|
||||
import (
|
||||
"github.com/julienschmidt/httprouter"
|
||||
"github.com/mchackorg/birdwatcher/bird"
|
||||
)
|
||||
|
||||
func Protocols(ps httprouter.Params) bird.Parsed {
|
||||
return bird.Protocols()
|
||||
}
|
||||
|
||||
func Bgp(ps httprouter.Params) bird.Parsed {
|
||||
return bird.ProtocolsBgp()
|
||||
}
|
30
endpoints/routes.go
Normal file
30
endpoints/routes.go
Normal file
|
@ -0,0 +1,30 @@
|
|||
package endpoints
|
||||
|
||||
import (
|
||||
"github.com/julienschmidt/httprouter"
|
||||
"github.com/mchackorg/birdwatcher/bird"
|
||||
)
|
||||
|
||||
func ProtoRoutes(ps httprouter.Params) bird.Parsed {
|
||||
return bird.RoutesProto(ps.ByName("protocol"))
|
||||
}
|
||||
|
||||
func TableRoutes(ps httprouter.Params) bird.Parsed {
|
||||
return bird.RoutesTable(ps.ByName("table"))
|
||||
}
|
||||
|
||||
func ProtoCount(ps httprouter.Params) bird.Parsed {
|
||||
return bird.RoutesProtoCount(ps.ByName("protocol"))
|
||||
}
|
||||
|
||||
func TableCount(ps httprouter.Params) bird.Parsed {
|
||||
return bird.RoutesTable(ps.ByName("table"))
|
||||
}
|
||||
|
||||
func RouteNet(ps httprouter.Params) bird.Parsed {
|
||||
return bird.RoutesLookupTable(ps.ByName("net"), "master")
|
||||
}
|
||||
|
||||
func RouteNetTable(ps httprouter.Params) bird.Parsed {
|
||||
return bird.RoutesLookupTable(ps.ByName("net"), ps.ByName("table"))
|
||||
}
|
10
endpoints/status.go
Normal file
10
endpoints/status.go
Normal file
|
@ -0,0 +1,10 @@
|
|||
package endpoints
|
||||
|
||||
import (
|
||||
"github.com/julienschmidt/httprouter"
|
||||
"github.com/mchackorg/birdwatcher/bird"
|
||||
)
|
||||
|
||||
func Status(ps httprouter.Params) bird.Parsed {
|
||||
return bird.Status()
|
||||
}
|
18
endpoints/symbols.go
Normal file
18
endpoints/symbols.go
Normal file
|
@ -0,0 +1,18 @@
|
|||
package endpoints
|
||||
|
||||
import (
|
||||
"github.com/julienschmidt/httprouter"
|
||||
"github.com/mchackorg/birdwatcher/bird"
|
||||
)
|
||||
|
||||
func Symbols(ps httprouter.Params) bird.Parsed {
|
||||
return bird.Symbols()
|
||||
}
|
||||
|
||||
func SymbolTables(ps httprouter.Params) bird.Parsed {
|
||||
return bird.Parsed{"symbols": bird.Symbols()["routing table"]}
|
||||
}
|
||||
|
||||
func SymbolProtocols(ps httprouter.Params) bird.Parsed {
|
||||
return bird.Parsed{"symbols": bird.Symbols()["protocols"]}
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package main
|
||||
package endpoints
|
||||
|
||||
type TimeInfo struct {
|
||||
Date string `json:"date"`
|
79
patterns.go
79
patterns.go
|
@ -1,79 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"fmt"
|
||||
"os"
|
||||
)
|
||||
|
||||
// readLines reads a whole file into memory
|
||||
// and returns a slice of its lines.
|
||||
func readLines(path string) ([]string, error) {
|
||||
file, err := os.Open(path)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
defer file.Close()
|
||||
|
||||
var lines []string
|
||||
scanner := bufio.NewScanner(file)
|
||||
for scanner.Scan() {
|
||||
lines = append(lines, scanner.Text())
|
||||
}
|
||||
return lines, scanner.Err()
|
||||
}
|
||||
|
||||
// pattern looks for pattern matching regular expression re in the
|
||||
// lines buffer. Returns the name of our next regular expression to
|
||||
// look for.
|
||||
func pattern(first string, lines []string) (maplist []map[string]string) {
|
||||
var re RE
|
||||
var fieldmap map[string]string
|
||||
|
||||
fmt.Printf("In pattern\n")
|
||||
|
||||
re, ok := conf.Res[first]
|
||||
if !ok {
|
||||
slog.Debug("Couldn't find first state.")
|
||||
return
|
||||
}
|
||||
|
||||
// Store away all the fields in a map.
|
||||
fieldmap = make(map[string]string)
|
||||
|
||||
for _, line := range lines {
|
||||
if debug > 1 {
|
||||
slog.Debug("Looking at: " + line)
|
||||
}
|
||||
|
||||
fields := re.RE.FindStringSubmatch(line)
|
||||
|
||||
if len(fields)-1 == len(re.Match.Fields) {
|
||||
if debug > 0 {
|
||||
line := fmt.Sprintf("Found match for a message of type '%v'", re.Match)
|
||||
slog.Debug(line)
|
||||
}
|
||||
for key, name := range re.Match.Fields {
|
||||
if debug > 0 {
|
||||
slog.Debug("Got " + re.Match.Fields[key])
|
||||
}
|
||||
fieldmap[name] = fields[key+1]
|
||||
}
|
||||
|
||||
if re.Match.Action == "send" {
|
||||
// Finished for this item. Create a new field map and add this to the list.
|
||||
maplist = append(maplist, fieldmap)
|
||||
fieldmap = make(map[string]string)
|
||||
}
|
||||
|
||||
// Go to the next state, if it exists. If it
|
||||
// doesn't we're finished here.
|
||||
re, ok = conf.Res[re.Match.Next]
|
||||
if !ok {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return maplist
|
||||
}
|
35
protocols.go
35
protocols.go
|
@ -1,35 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
|
||||
"github.com/julienschmidt/httprouter"
|
||||
"github.com/mchackorg/birdwatcher/bird"
|
||||
)
|
||||
|
||||
func Protocols(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
res := make(map[string]interface{})
|
||||
|
||||
res["api"] = GetApiInfo()
|
||||
|
||||
res["protocols"] = bird.Protocols()["protocols"]
|
||||
|
||||
js, _ := json.Marshal(res)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(js)
|
||||
}
|
||||
|
||||
func Bgp(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
res := make(map[string]interface{})
|
||||
|
||||
res["api"] = GetApiInfo()
|
||||
|
||||
res["protocols"] = bird.ProtocolsBgp()
|
||||
|
||||
js, _ := json.Marshal(res)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(js)
|
||||
}
|
83
routes.go
83
routes.go
|
@ -1,83 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
"github.com/mchackorg/birdwatcher/bird"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func ProtoRoutes(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
res := make(map[string]interface{})
|
||||
|
||||
res["api"] = GetApiInfo()
|
||||
res["routes"] = bird.RoutesProto(ps.ByName("protocol"))["routes"]
|
||||
|
||||
js, _ := json.Marshal(res)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(js)
|
||||
}
|
||||
|
||||
func TableRoutes(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
res := make(map[string]interface{})
|
||||
|
||||
res["api"] = GetApiInfo()
|
||||
res["routes"] = bird.RoutesTable(ps.ByName("table"))["routes"]
|
||||
|
||||
js, _ := json.Marshal(res)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(js)
|
||||
}
|
||||
|
||||
func ProtoCount(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
res := make(map[string]interface{})
|
||||
|
||||
res["api"] = GetApiInfo()
|
||||
res["count"] = bird.RoutesProtoCount(ps.ByName("protocol"))
|
||||
|
||||
js, _ := json.Marshal(res)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(js)
|
||||
}
|
||||
|
||||
func TableCount(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
res := make(map[string]interface{})
|
||||
|
||||
res["api"] = GetApiInfo()
|
||||
res["count"] = bird.RoutesTable(ps.ByName("table"))
|
||||
|
||||
js, _ := json.Marshal(res)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(js)
|
||||
}
|
||||
|
||||
func RouteNet(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
res := make(map[string]interface{})
|
||||
|
||||
res["api"] = GetApiInfo()
|
||||
res["routes"] = bird.RoutesLookupTable(ps.ByName("net"), "master")
|
||||
|
||||
js, _ := json.Marshal(res)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(js)
|
||||
}
|
||||
|
||||
func RouteNetTable(w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
ps httprouter.Params) {
|
||||
res := make(map[string]interface{})
|
||||
|
||||
res["api"] = GetApiInfo()
|
||||
res["routes"] = bird.RoutesLookupTable(ps.ByName("net"),
|
||||
ps.ByName("table"))
|
||||
|
||||
js, _ := json.Marshal(res)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(js)
|
||||
}
|
21
status.go
21
status.go
|
@ -1,21 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
"github.com/mchackorg/birdwatcher/bird"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func Status(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
res := make(map[string]interface{})
|
||||
|
||||
res["api"] = GetApiInfo()
|
||||
|
||||
res["status"] = bird.Status()
|
||||
|
||||
js, _ := json.Marshal(res)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(js)
|
||||
}
|
51
symbols.go
51
symbols.go
|
@ -1,51 +0,0 @@
|
|||
package main
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
"github.com/mchackorg/birdwatcher/bird"
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func Symbols(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
res := make(map[string]interface{})
|
||||
|
||||
res["api"] = GetApiInfo()
|
||||
|
||||
res["symbols"] = bird.Symbols()
|
||||
|
||||
js, _ := json.Marshal(res)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(js)
|
||||
}
|
||||
|
||||
func SymbolTables(w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
ps httprouter.Params) {
|
||||
res := make(map[string]interface{})
|
||||
|
||||
res["api"] = GetApiInfo()
|
||||
|
||||
res["symbols"] = bird.Symbols()["routing table"]
|
||||
|
||||
js, _ := json.Marshal(res)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(js)
|
||||
}
|
||||
|
||||
func SymbolProtocols(w http.ResponseWriter,
|
||||
r *http.Request,
|
||||
ps httprouter.Params) {
|
||||
res := make(map[string]interface{})
|
||||
|
||||
res["api"] = GetApiInfo()
|
||||
|
||||
res["symbols"] = bird.Symbols()["protocol"]
|
||||
|
||||
js, _ := json.Marshal(res)
|
||||
|
||||
w.Header().Set("Content-Type", "application/json")
|
||||
w.Write(js)
|
||||
}
|
File diff suppressed because it is too large
Load diff
Loading…
Add table
Reference in a new issue