1
0
Fork 0
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:
hellerve 2017-02-22 11:24:50 +01:00
commit ac5304c413
12 changed files with 118 additions and 23 deletions

View file

@ -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)

View file

@ -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

View file

@ -1 +1 @@
1.7.0
1.7.8

View file

@ -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)
}

View file

@ -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
}

View file

@ -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 {

View file

@ -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 {

View file

@ -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{

View file

@ -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))
}
}

View file

@ -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)
}

View file

@ -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

View file

@ -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]
#