alice-lg/pkg/api/response.go

326 lines
8.0 KiB
Go

package api
import (
"strconv"
"time"
)
// A Response is a general API response. All API responses
// contain meta information with API version and caching
// information.
type Response struct {
Meta *Meta `json:"api"`
}
// ErrorResponse encodes an error message and code
type ErrorResponse struct {
Message string `json:"message"`
Code int `json:"code"`
Tag string `json:"tag"`
RouteserverID string `json:"routeserver_id"`
}
// CacheableResponse is a cache aware API response
type CacheableResponse interface {
CacheTTL() time.Duration
}
// ConfigResponse is a response with client runtime configuration
type ConfigResponse struct {
RejectReasons map[string]interface{} `json:"reject_reasons"`
Noexport Noexport `json:"noexport"`
NoexportReasons map[string]interface{} `json:"noexport_reasons"`
RejectCandidates RejectCandidates `json:"reject_candidates"`
Rpki Rpki `json:"rpki"`
BGPCommunities map[string]interface{} `json:"bgp_communities"`
BGPBlackholeCommunities BGPCommunitiesSet `json:"bgp_blackhole_communities"`
NeighborsColumns map[string]string `json:"neighbors_columns"`
NeighborsColumnsOrder []string `json:"neighbors_columns_order"`
RoutesColumns map[string]string `json:"routes_columns"`
RoutesColumnsOrder []string `json:"routes_columns_order"`
LookupColumns map[string]string `json:"lookup_columns"`
LookupColumnsOrder []string `json:"lookup_columns_order"`
PrefixLookupEnabled bool `json:"prefix_lookup_enabled"`
}
// Noexport options
type Noexport struct {
LoadOnDemand bool `json:"load_on_demand"`
}
// RejectCandidates contains a communities mapping
// of reasons for a rejection in the future.
type RejectCandidates struct {
Communities map[string]interface{} `json:"communities"`
}
// Rpki is the validation status of a prefix
type Rpki struct {
Enabled bool `json:"enabled"`
Valid [][]string `json:"valid"`
Unknown [][]string `json:"unknown"`
NotChecked [][]string `json:"not_checked"`
Invalid [][]string `json:"invalid"`
}
// Meta contains response meta information
// like cacheing time and cache ttl or the API version
type Meta struct {
Version string `json:"version"`
CacheStatus CacheStatus `json:"cache_status"`
ResultFromCache bool `json:"result_from_cache"`
TTL time.Time `json:"ttl"`
StoreStatus *StoreStatusMeta `json:"store_status,omitempty"`
}
// CacheStatus contains cache timing information.
type CacheStatus struct {
CachedAt time.Time `json:"cached_at"`
OrigTTL int `json:"orig_ttl"`
}
// SourceStatus is the current status of a source in
// a store.
type SourceStatus struct {
RefreshInterval time.Duration `json:"refresh_interval"`
LastRefresh time.Time `json:"last_refresh"`
State string `json:"state"`
Initialized bool `json:"initialized"`
}
// StoreStatus is meta data for a store
type StoreStatus struct {
Initialized bool `json:"initialized"`
Sources map[string]*SourceStatus `json:"sources"`
}
// StoreStatusMeta is the meta response for all stores
type StoreStatusMeta struct {
Routes *StoreStatus `json:"routes,omitempty"`
Neighbors *StoreStatus `json:"neighbors,omitempty"`
}
// Status ... TODO: ?
type Status struct {
ServerTime time.Time `json:"server_time"`
LastReboot time.Time `json:"last_reboot"`
LastReconfig time.Time `json:"last_reconfig"`
Message string `json:"message"`
RouterID string `json:"router_id"`
Version string `json:"version"`
Backend string `json:"backend"`
}
// StatusResponse ??
type StatusResponse struct {
Response
Status Status `json:"status"`
}
// A RouteServer is a datasource with attributes.
type RouteServer struct {
ID string `json:"id"`
Type string `json:"type"`
Name string `json:"name"`
Group string `json:"group"`
Blackholes []string `json:"blackholes"`
Order int `json:"-"`
}
// RouteServers is a collection of routeservers.
type RouteServers []RouteServer
// Len implements sorting interface for routeservers
func (rs RouteServers) Len() int {
return len(rs)
}
func (rs RouteServers) Less(i, j int) bool {
return rs[i].Order < rs[j].Order
}
func (rs RouteServers) Swap(i, j int) {
rs[i], rs[j] = rs[j], rs[i]
}
// A RouteServersResponse contains a list of routeservers.
type RouteServersResponse struct {
RouteServers RouteServers `json:"routeservers"`
}
// A LookupRouteServer is a shorter representation of the
// route server data source.
type LookupRouteServer struct {
ID *string `json:"id"`
Name string `json:"name"`
}
// Community is a BGP community
type Community []int
func (com Community) String() string {
if len(com) < 1 {
return ""
}
s := ""
for i, v := range com {
if i > 0 {
s += ":"
}
s += strconv.Itoa(v)
}
return s
}
// Communities is a collection of bgp communities
type Communities []Community
// Unique deduplicates communities.
/*
We can skip this. Worst case is, that the
cardinality is off.
func (communities Communities) Unique() Communities {
seen := map[string]bool{}
result := make(Communities, 0, len(communities))
for _, com := range communities {
key := com.String()
if _, ok := seen[key]; !ok {
// We have not seen this community yet
result = append(result, com)
seen[key] = true
}
}
return result
}
*/
// ExtCommunity is a BGP extended community
type ExtCommunity []interface{}
func (com ExtCommunity) String() string {
if len(com) < 1 {
return ""
}
res := ""
for i, v := range com {
if i == 0 {
res += v.(string)
continue
}
if i > 0 {
res += ":"
}
res += strconv.Itoa(v.(int))
}
return res
}
// ExtCommunities is a collection of extended bgp communities.
type ExtCommunities []ExtCommunity
// Unique deduplicates extended communities.
/*
func (communities ExtCommunities) Unique() ExtCommunities {
seen := map[string]bool{}
result := make(ExtCommunities, 0, len(communities))
for _, com := range communities {
key := com.String()
if _, ok := seen[key]; !ok {
// We have not seen this community yet
result = append(result, com)
seen[key] = true
}
}
return result
}
*/
// BGPInfo is a set of BGP attributes
type BGPInfo struct {
Origin *string `json:"origin"`
AsPath []int `json:"as_path"`
NextHop *string `json:"next_hop"`
Communities Communities `json:"communities"`
LargeCommunities Communities `json:"large_communities"`
ExtCommunities ExtCommunities `json:"ext_communities"`
LocalPref int `json:"local_pref"`
Med int `json:"med"`
}
// HasCommunity checks for the presence of a BGP community.
func (bgp *BGPInfo) HasCommunity(community Community) bool {
if len(community) != 2 {
return false // This can never match.
}
for _, com := range bgp.Communities {
if len(com) != len(community) {
continue // This can't match.
}
if com[0] == community[0] &&
com[1] == community[1] {
return true
}
}
return false
}
// HasExtCommunity checks for the presence of an
// extended community.
func (bgp *BGPInfo) HasExtCommunity(community ExtCommunity) bool {
if len(community) != 3 {
return false // This can never match.
}
for _, com := range bgp.ExtCommunities {
if len(com) != len(community) {
continue // This can't match.
}
if com[0] == community[0] &&
com[1] == community[1] &&
com[2] == community[2] {
return true
}
}
return false
}
// HasLargeCommunity checks for the presence of a large community.
func (bgp *BGPInfo) HasLargeCommunity(community Community) bool {
// TODO: This is an almost 1:1 match to the function above.
if len(community) != 3 {
return false // This can never match.
}
for _, com := range bgp.LargeCommunities {
if len(com) != len(community) {
continue // This can't match.
}
if com[0] == community[0] &&
com[1] == community[1] &&
com[2] == community[2] {
return true
}
}
return false
}