mirror of
https://github.com/alice-lg/birdwatcher.git
synced 2025-03-09 00:00:05 +01:00
Merge branch 'master' into filter-meta
* master: bugfix: readded ttl to bgp protocol bugfix: timestamps only had date in them added large communities to possible bgp values added exported routes to peer version bump: get actual birdwatcher version in request moved why to top added section on building an rpm and deployment added more elaborate installation and configuration instructions version bump better regex for route parsing ("via" line) removed useless print vbump only use key once bugfixing the bugfix bugfix: make ratelimiting robust in nested calls version bump hotfix: caching should reset
This commit is contained in:
commit
ac5304c413
12 changed files with 118 additions and 23 deletions
3
Makefile
3
Makefile
|
@ -1,4 +1,3 @@
|
|||
|
||||
#
|
||||
# Ecix Birdseye Makefile
|
||||
#
|
||||
|
@ -99,5 +98,3 @@ clean:
|
|||
rm -f $(PROG)-osx-$(ARCH)
|
||||
rm -f $(PROG)-linux-$(ARCH)
|
||||
rm -rf $(DIST)
|
||||
|
||||
|
||||
|
|
49
README.md
49
README.md
|
@ -5,13 +5,6 @@ Barry O'Donovan's
|
|||
[birds-eye](https://github.com/inex/birds-eye-design/) to
|
||||
[the BIRD routing daemon](http://bird.network.cz/).
|
||||
|
||||
## Installation
|
||||
|
||||
You will need to have go installed to build the package.
|
||||
Running `go get github.com/ecix/birdwatcher` will give you
|
||||
a binary. You might need to cross-compile it for your
|
||||
bird-running servive (`GOARCH` and `GOOS` are your friends).
|
||||
|
||||
## Why
|
||||
|
||||
The [INEX implementation](https://github.com/inex/birdseye) of
|
||||
|
@ -20,6 +13,48 @@ in a routeserver setting. By using Go, we are able to work with
|
|||
regular binaries, which means deployment and maintenance might be
|
||||
more convenient.
|
||||
|
||||
Our version also has a few more capabilities, as you will
|
||||
discover when looking at [the modules section](https://github.com/ecix/birdwatcher/blob/master/etc/ecix/birdwatcher.conf)
|
||||
of the config.
|
||||
|
||||
## Installation
|
||||
|
||||
You will need to have go installed to build the package.
|
||||
Running `go get github.com/ecix/birdwatcher` will give you
|
||||
a binary. You might need to cross-compile it for your
|
||||
bird-running servive (`GOARCH` and `GOOS` are your friends).
|
||||
|
||||
We provide a Makefile for more advanced compilation/configuration.
|
||||
Running `make linux` will create a Linux executable (by default for
|
||||
`amd64`, but that is configurable by providing the `ARCH` argument
|
||||
to the Makefile).
|
||||
|
||||
### Building an RPM
|
||||
|
||||
Building RPMs is supported through [fpm](https://github.com/jordansissel/fpm).
|
||||
If you have `fpm` installed locally, you can run `make rpm`
|
||||
to create a RPM in the folder `RPMS`. If you have a remote
|
||||
build server with `fpm` installed, you can build and fetch
|
||||
an RPM with `make remote_rpm BUILD_SERVER=<buildserver_url>`
|
||||
(requires SSH access).
|
||||
|
||||
### Deployment
|
||||
|
||||
If you want to deploy `birdwatcher` on a system that uses
|
||||
RPMs, you should be able to install it after following the
|
||||
instructions on [building an RPM](#building-an-rpm).
|
||||
|
||||
We do not currently support other deployment methods.
|
||||
|
||||
## Configuration
|
||||
|
||||
An example config with sane defaults is provided in
|
||||
[etc/ecix/birdwatcher.conf](https://github.com/ecix/birdwatcher/blob/master/etc/ecix/birdwatcher.conf).
|
||||
You should be able to use it out of the box. If you need
|
||||
to change it, it is well-commented and hopefully intuitive.
|
||||
If you do not know how to configure it, please consider opening
|
||||
[an issue](https://github.com/ecix/birdwatcher/issues/new).
|
||||
|
||||
## How
|
||||
|
||||
In the background `birdwatcher` runs the `birdc` client, sends
|
||||
|
|
2
VERSION
2
VERSION
|
@ -1 +1 @@
|
|||
1.7.0
|
||||
1.7.8
|
||||
|
|
22
bird/bird.go
22
bird/bird.go
|
@ -23,6 +23,15 @@ func fromCache(key string) (Parsed, bool) {
|
|||
Cache.RLock()
|
||||
val, ok := Cache.m[key]
|
||||
Cache.RUnlock()
|
||||
if !ok {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
ttl, correct := val["ttl"].(time.Time)
|
||||
if !correct || ttl.Before(time.Now()) {
|
||||
return nil, false
|
||||
}
|
||||
|
||||
return val, ok
|
||||
}
|
||||
|
||||
|
@ -96,6 +105,9 @@ func RunAndParse(cmd string, parser func([]byte) Parsed) (Parsed, bool) {
|
|||
|
||||
func Status() (Parsed, bool) {
|
||||
birdStatus, ok := RunAndParse("status", parseStatus)
|
||||
if birdStatus == nil {
|
||||
return birdStatus, ok
|
||||
}
|
||||
status := birdStatus["status"].(Parsed)
|
||||
|
||||
// Last Reconfig Timestamp source:
|
||||
|
@ -133,6 +145,9 @@ func Protocols() (Parsed, bool) {
|
|||
|
||||
func ProtocolsBgp() (Parsed, bool) {
|
||||
p, from_cache := Protocols()
|
||||
if p == nil {
|
||||
return p, from_cache
|
||||
}
|
||||
protocols := p["protocols"].([]string)
|
||||
|
||||
bgpProto := Parsed{}
|
||||
|
@ -144,7 +159,8 @@ func ProtocolsBgp() (Parsed, bool) {
|
|||
}
|
||||
}
|
||||
|
||||
return Parsed{"protocols": bgpProto}, from_cache
|
||||
|
||||
return Parsed{"protocols": bgpProto, "ttl": p["ttl"]}, from_cache
|
||||
}
|
||||
|
||||
func Symbols() (Parsed, bool) {
|
||||
|
@ -198,3 +214,7 @@ func RoutesLookupProtocol(net string, protocol string) (Parsed, bool) {
|
|||
return RunAndParse("route for '"+net+"' protocol '"+protocol+"' all",
|
||||
parseRoutes)
|
||||
}
|
||||
|
||||
func RoutesPeer(peer string) (Parsed, bool) {
|
||||
return RunAndParse("route export '"+peer+"'", parseRoutes)
|
||||
}
|
||||
|
|
|
@ -16,7 +16,7 @@ type BirdConfig struct {
|
|||
}
|
||||
|
||||
type RateLimitConfig struct {
|
||||
Reqs int `toml:"requests_per_minute"`
|
||||
Reqs int
|
||||
Max int `toml:"requests_per_minute"`
|
||||
Enabled bool
|
||||
}
|
||||
|
|
|
@ -46,9 +46,9 @@ func parseStatus(input []byte) Parsed {
|
|||
|
||||
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*$`)
|
||||
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) {
|
||||
|
@ -128,10 +128,11 @@ func parseRoutes(input []byte) Parsed {
|
|||
|
||||
route := Parsed{}
|
||||
start_def_rx := regexp.MustCompile(`^([0-9a-f\.\:\/]+)\s+via\s+([0-9a-f\.\:]+)\s+on\s+(\w+)\s+\[([\w\.:]+)\s+([0-9\-\:\s]+)(?:\s+from\s+([0-9a-f\.\:\/]+)){0,1}\]\s+(?:(\*)\s+){0,1}\((\d+)(?:\/\d+){0,1}\).*`)
|
||||
second_rx := regexp.MustCompile(`^\s+via\s+([0-9a-f\.\:]+)\s+on\s+(\w+)\s+\[(\w+)\s+([0-9\-\:]+)(?:\s+from\s+([0-9a-f\.\:\/]+)){0,1}\]\s+(?:(\*)\s+){0,1}\((\d+)(?:\/\d+){0,1}\).*$`)
|
||||
second_rx := regexp.MustCompile(`^\s+via\s+([0-9a-f\.\:]+)\s+on\s+([\w+)\s+\[([\w\.]+)\s+([0-9\-\:\s]+)(?:\s+from\s+([0-9a-f\.\:\/]+)){0,1}\]\s+(?:(\*)\s+){0,1}\((\d+)(?:\/\d+){0,1}\).*$`)
|
||||
type_rx := regexp.MustCompile(`^\s+Type:\s+(.*)\s*$`)
|
||||
bgp_rx := regexp.MustCompile(`^\s+BGP.(\w+):\s+(.+)\s*$`)
|
||||
community_rx := regexp.MustCompile(`^\((\d+),(\d+)\)`)
|
||||
large_community_rx := regexp.MustCompile(`^\((\d+),(\d+),(\d+)\)`)
|
||||
for _, line := range lines {
|
||||
if specialLine(line) || (len(route) == 0 && emptyLine(line)) {
|
||||
continue
|
||||
|
@ -186,6 +187,18 @@ func parseRoutes(input []byte) Parsed {
|
|||
}
|
||||
}
|
||||
bgp["communities"] = communities
|
||||
} else if groups[1] == "large_community" {
|
||||
communities := [][]int64{}
|
||||
for _, community := range strings.Split(groups[2], " ") {
|
||||
if large_community_rx.MatchString(community) {
|
||||
com_groups := large_community_rx.FindStringSubmatch(community)
|
||||
maj := parseInt(com_groups[1])
|
||||
min := parseInt(com_groups[2])
|
||||
pat := parseInt(com_groups[3])
|
||||
communities = append(communities, []int64{maj, min, pat})
|
||||
}
|
||||
}
|
||||
bgp["large_communities"] = communities
|
||||
} else if groups[1] == "as_path" {
|
||||
bgp["as_path"] = strings.Split(groups[2], " ")
|
||||
} else {
|
||||
|
|
|
@ -24,8 +24,6 @@ func lastReconfigTimestampFromFileStat(filename string) string {
|
|||
func lastReconfigTimestampFromFileContent(filename string, regex string) string {
|
||||
rx := regexp.MustCompile(regex)
|
||||
|
||||
fmt.Println("Using regex:", regex)
|
||||
|
||||
// Read config file linewise
|
||||
file, err := os.Open(filename)
|
||||
if err != nil {
|
||||
|
|
|
@ -12,6 +12,9 @@ import (
|
|||
"github.com/julienschmidt/httprouter"
|
||||
)
|
||||
|
||||
//go:generate versionize
|
||||
var VERSION = "1.7.8"
|
||||
|
||||
func isModuleEnabled(module string, modulesEnabled []string) bool {
|
||||
for _, enabled := range modulesEnabled {
|
||||
if enabled == module {
|
||||
|
@ -26,6 +29,7 @@ func makeRouter(config endpoints.ServerConfig) *httprouter.Router {
|
|||
|
||||
r := httprouter.New()
|
||||
if isModuleEnabled("status", whitelist) {
|
||||
r.GET("/version", endpoints.Version(VERSION))
|
||||
r.GET("/status", endpoints.Endpoint(endpoints.Status))
|
||||
}
|
||||
if isModuleEnabled("protocols", whitelist) {
|
||||
|
@ -65,6 +69,9 @@ func makeRouter(config endpoints.ServerConfig) *httprouter.Router {
|
|||
r.GET("/route/net/:net", endpoints.Endpoint(endpoints.RouteNet))
|
||||
r.GET("/route/net/:net/table/:table", endpoints.Endpoint(endpoints.RouteNetTable))
|
||||
}
|
||||
if isModuleEnabled("routes_peer", whitelist) {
|
||||
r.GET("/routes/peer", endpoints.Endpoint(endpoints.RoutesPeer))
|
||||
}
|
||||
return r
|
||||
}
|
||||
|
||||
|
@ -93,6 +100,7 @@ func main() {
|
|||
bird6 := flag.Bool("6", false, "Use bird6 instead of bird")
|
||||
flag.Parse()
|
||||
|
||||
endpoints.VERSION = VERSION
|
||||
bird.InstallRateLimitReset()
|
||||
// Load configurations
|
||||
conf, err := LoadConfigs([]string{
|
||||
|
|
|
@ -70,3 +70,10 @@ func Endpoint(wrapped endpoint) httprouter.Handle {
|
|||
w.Write(js)
|
||||
}
|
||||
}
|
||||
|
||||
func Version(version string) httprouter.Handle {
|
||||
return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
|
||||
w.Header().Set("Content-Type", "text/plain")
|
||||
w.Write([]byte(version))
|
||||
}
|
||||
}
|
||||
|
|
|
@ -61,3 +61,17 @@ func RouteNet(r *http.Request, ps httprouter.Params) (bird.Parsed, bool) {
|
|||
func RouteNetTable(r *http.Request, ps httprouter.Params) (bird.Parsed, bool) {
|
||||
return bird.RoutesLookupTable(ps.ByName("net"), ps.ByName("table"))
|
||||
}
|
||||
|
||||
func RoutesPeer(r *http.Request, ps httprouter.Params) (bird.Parsed, bool) {
|
||||
qs := r.URL.Query()
|
||||
peerl := qs["peer"]
|
||||
if len(peerl) != 1 {
|
||||
return bird.Parsed{"error": "need a peer as single query parameter"}, false
|
||||
}
|
||||
|
||||
peer, err := ValidateProtocolParam(peerl[0])
|
||||
if err != nil {
|
||||
return bird.Parsed{"error": fmt.Sprintf("%s", err)}, false
|
||||
}
|
||||
return bird.RoutesPeer(peer)
|
||||
}
|
||||
|
|
|
@ -17,10 +17,13 @@ type APIInfo struct {
|
|||
CacheStatus CacheStatus `json:"cache_status"`
|
||||
}
|
||||
|
||||
// go generate does not work in subdirectories. Beautious.
|
||||
var VERSION string
|
||||
|
||||
func GetApiInfo(from_cache bool) *APIInfo {
|
||||
ai := &APIInfo{}
|
||||
|
||||
ai.Version = "1.0"
|
||||
ai.Version = VERSION
|
||||
ai.ResultFromCache = from_cache
|
||||
|
||||
return ai
|
||||
|
|
|
@ -3,10 +3,10 @@
|
|||
#
|
||||
|
||||
[server]
|
||||
# Restrict access to certain IPs. Leave empty to allow from all.
|
||||
# Restrict access to certain IPs. Leave empty to allow from all.
|
||||
allow_from = []
|
||||
|
||||
# All modules:
|
||||
# All modules:
|
||||
# status
|
||||
# protocols
|
||||
# protocols_bgp
|
||||
|
@ -21,7 +21,7 @@ allow_from = []
|
|||
# routes_filtered
|
||||
# routes_prefixed
|
||||
#
|
||||
modules_enabled = ["status", "protocols_bgp", "routes_protocol"]
|
||||
modules_enabled = ["status", "protocols_bgp", "routes_protocol", "routes_peer"]
|
||||
|
||||
[status]
|
||||
#
|
||||
|
|
Loading…
Add table
Reference in a new issue