diff --git a/bird/bird.go b/bird/bird.go index c5c2a3d..3d2bc83 100644 --- a/bird/bird.go +++ b/bird/bird.go @@ -3,37 +3,66 @@ package bird import ( "os/exec" "strings" + "time" + "sync" ) var BirdCmd string +var Cache = struct{ + sync.RWMutex + m map[string]Parsed +}{m: make(map[string]Parsed)} + +func fromCache(key string) (Parsed, bool) { + Cache.RLock() + val, ok := Cache.m[key] + Cache.RUnlock() + return val, ok +} + +func toCache(key string, val Parsed) { + val["ttl"] = time.Now().Add(5 * time.Minute) + Cache.Lock() + Cache.m[key] = val + Cache.Unlock() +} + + func Run(args string) ([]byte, error) { args = "show " + args argsList := strings.Split(args, " ") return exec.Command(BirdCmd, argsList...).Output() } -func RunAndParse(cmd string, parser func([]byte) Parsed) Parsed { +func RunAndParse(cmd string, parser func([]byte) Parsed) (Parsed, bool) { + if val, ok := fromCache(cmd); ok { + return val, true + } + out, err := Run(cmd) if err != nil { // ignore errors for now - return Parsed{} + return Parsed{}, false } - return parser(out) + parsed := parser(out) + toCache(cmd, parsed) + return parsed, false } -func Status() Parsed { +func Status() (Parsed, bool) { return RunAndParse("status", parseStatus) } -func Protocols() Parsed { +func Protocols() (Parsed, bool) { return RunAndParse("protocols all", parseProtocols) } -func ProtocolsBgp() Parsed { - protocols := Protocols()["protocols"].([]string) +func ProtocolsBgp() (Parsed, bool) { + p, from_cache := Protocols() + protocols := p["protocols"].([]string) bgpProto := Parsed{} @@ -44,49 +73,49 @@ func ProtocolsBgp() Parsed { } } - return Parsed{"protocols": bgpProto} + return Parsed{"protocols": bgpProto}, from_cache } -func Symbols() Parsed { +func Symbols() (Parsed, bool) { return RunAndParse("symbols", parseSymbols) } -func RoutesProto(protocol string) Parsed { +func RoutesProto(protocol string) (Parsed, bool) { return RunAndParse("route protocol "+protocol+" all", parseRoutes) } -func RoutesProtoCount(protocol string) Parsed { +func RoutesProtoCount(protocol string) (Parsed, bool) { return RunAndParse("route protocol "+protocol+" count", parseRoutesCount) } -func RoutesExport(protocol string) Parsed { +func RoutesExport(protocol string) (Parsed, bool) { return RunAndParse("route export "+protocol+" all", parseRoutes) } -func RoutesExportCount(protocol string) Parsed { +func RoutesExportCount(protocol string) (Parsed, bool) { return RunAndParse("route export "+protocol+" count", parseRoutesCount) } -func RoutesTable(table string) Parsed { +func RoutesTable(table string) (Parsed, bool) { return RunAndParse("route table "+table+" all", parseRoutes) } -func RoutesTableCount(table string) Parsed { +func RoutesTableCount(table string) (Parsed, bool) { return RunAndParse("route table "+table+" count", parseRoutesCount) } -func RoutesLookupTable(net string, table string) Parsed { +func RoutesLookupTable(net string, table string) (Parsed, bool) { return RunAndParse("route for "+net+" table "+table+" all", parseRoutes) } -func RoutesLookupProtocol(net string, protocol string) Parsed { +func RoutesLookupProtocol(net string, protocol string) (Parsed, bool) { return RunAndParse("route for "+net+" protocol "+protocol+" all", parseRoutes) } diff --git a/endpoints/endpoint.go b/endpoints/endpoint.go index fea8c17..e27ee35 100644 --- a/endpoints/endpoint.go +++ b/endpoints/endpoint.go @@ -8,15 +8,14 @@ import ( "github.com/julienschmidt/httprouter" ) -func Endpoint(wrapped func(httprouter.Params) bird.Parsed) httprouter.Handle { +func Endpoint(wrapped func(httprouter.Params) (bird.Parsed, bool)) httprouter.Handle { return func(w http.ResponseWriter, r *http.Request, ps httprouter.Params) { res := make(map[string]interface{}) - res["api"] = GetApiInfo() - - ret := wrapped(ps) + ret, from_cache := wrapped(ps) + res["api"] = GetApiInfo(from_cache) for k, v := range ret { res[k] = v diff --git a/endpoints/protocols.go b/endpoints/protocols.go index c3b038b..cfc7a9c 100644 --- a/endpoints/protocols.go +++ b/endpoints/protocols.go @@ -5,10 +5,10 @@ import ( "github.com/julienschmidt/httprouter" ) -func Protocols(ps httprouter.Params) bird.Parsed { +func Protocols(ps httprouter.Params) (bird.Parsed, bool) { return bird.Protocols() } -func Bgp(ps httprouter.Params) bird.Parsed { +func Bgp(ps httprouter.Params) (bird.Parsed, bool) { return bird.ProtocolsBgp() } diff --git a/endpoints/routes.go b/endpoints/routes.go index b44d319..961d9b1 100644 --- a/endpoints/routes.go +++ b/endpoints/routes.go @@ -5,26 +5,26 @@ import ( "github.com/julienschmidt/httprouter" ) -func ProtoRoutes(ps httprouter.Params) bird.Parsed { +func ProtoRoutes(ps httprouter.Params) (bird.Parsed, bool) { return bird.RoutesProto(ps.ByName("protocol")) } -func TableRoutes(ps httprouter.Params) bird.Parsed { +func TableRoutes(ps httprouter.Params) (bird.Parsed, bool) { return bird.RoutesTable(ps.ByName("table")) } -func ProtoCount(ps httprouter.Params) bird.Parsed { +func ProtoCount(ps httprouter.Params) (bird.Parsed, bool) { return bird.RoutesProtoCount(ps.ByName("protocol")) } -func TableCount(ps httprouter.Params) bird.Parsed { +func TableCount(ps httprouter.Params) (bird.Parsed, bool) { return bird.RoutesTable(ps.ByName("table")) } -func RouteNet(ps httprouter.Params) bird.Parsed { +func RouteNet(ps httprouter.Params) (bird.Parsed, bool) { return bird.RoutesLookupTable(ps.ByName("net"), "master") } -func RouteNetTable(ps httprouter.Params) bird.Parsed { +func RouteNetTable(ps httprouter.Params) (bird.Parsed, bool) { return bird.RoutesLookupTable(ps.ByName("net"), ps.ByName("table")) } diff --git a/endpoints/status.go b/endpoints/status.go index 76f5d3b..63d6f55 100644 --- a/endpoints/status.go +++ b/endpoints/status.go @@ -5,6 +5,6 @@ import ( "github.com/julienschmidt/httprouter" ) -func Status(ps httprouter.Params) bird.Parsed { +func Status(ps httprouter.Params) (bird.Parsed, bool) { return bird.Status() } diff --git a/endpoints/symbols.go b/endpoints/symbols.go index 505195d..42367aa 100644 --- a/endpoints/symbols.go +++ b/endpoints/symbols.go @@ -5,14 +5,16 @@ import ( "github.com/julienschmidt/httprouter" ) -func Symbols(ps httprouter.Params) bird.Parsed { +func Symbols(ps httprouter.Params) (bird.Parsed, bool) { return bird.Symbols() } -func SymbolTables(ps httprouter.Params) bird.Parsed { - return bird.Parsed{"symbols": bird.Symbols()["routing table"]} +func SymbolTables(ps httprouter.Params) (bird.Parsed, bool) { + val, from_cache := bird.Symbols() + return bird.Parsed{"symbols": val["routing table"]}, from_cache } -func SymbolProtocols(ps httprouter.Params) bird.Parsed { - return bird.Parsed{"symbols": bird.Symbols()["protocols"]} +func SymbolProtocols(ps httprouter.Params) (bird.Parsed, bool) { + val, from_cache := bird.Symbols() + return bird.Parsed{"symbols": val["protocols"]}, from_cache } diff --git a/endpoints/utils.go b/endpoints/utils.go index 26ee70b..7fab85b 100644 --- a/endpoints/utils.go +++ b/endpoints/utils.go @@ -17,12 +17,11 @@ type APIInfo struct { CacheStatus CacheStatus `json:"cache_status"` } -func GetApiInfo() *APIInfo { +func GetApiInfo(from_cache bool) *APIInfo { ai := &APIInfo{} - /* Dummy data until we implement caching */ ai.Version = "1.0" - ai.ResultFromCache = false + ai.ResultFromCache = from_cache return ai }