added store status to response meta

This commit is contained in:
Annika Hannig 2022-07-27 18:00:31 +02:00
parent 2dccc56367
commit c1621589a2
6 changed files with 123 additions and 13 deletions

View File

@ -75,10 +75,11 @@ type Rpki struct {
// 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"`
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.
@ -87,6 +88,27 @@ type CacheStatus struct {
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"`

View File

@ -238,4 +238,6 @@ type PaginatedRoutesLookupResponse struct {
Imported *RoutesLookup `json:"imported"`
Filtered *RoutesLookup `json:"filtered"`
Status *StoreStatusMeta `json:"status"`
}

View File

@ -19,6 +19,10 @@ func (s *Server) apiLookupPrefixGlobal(
params httprouter.Params,
) (response, error) {
// TODO: This function is way too long
statusMeta := &api.StoreStatusMeta{
Neighbors: s.neighborsStore.Status(ctx),
Routes: s.routesStore.Status(ctx),
}
// Get prefix to query
q, err := validateQueryString(req, "q")
@ -127,6 +131,7 @@ func (s *Server) apiLookupPrefixGlobal(
CacheStatus: api.CacheStatus{
CachedAt: cachedAt,
},
StoreStatus: statusMeta,
ResultFromCache: true, // Well.
TTL: ttl,
},
@ -156,6 +161,10 @@ func (s *Server) apiLookupNeighborsGlobal(
req *http.Request,
params httprouter.Params,
) (response, error) {
statusMeta := &api.StoreStatusMeta{
Neighbors: s.neighborsStore.Status(ctx),
}
// Query neighbors store
filter := api.NeighborFilterFromQuery(req.URL.Query())
neighbors, err := s.neighborsStore.FilterNeighbors(ctx, filter)
@ -172,6 +181,7 @@ func (s *Server) apiLookupNeighborsGlobal(
CacheStatus: api.CacheStatus{
CachedAt: s.neighborsStore.CachedAt(ctx),
},
StoreStatus: statusMeta,
ResultFromCache: true, // You would not have guessed.
TTL: s.neighborsStore.CacheTTL(ctx),
},

View File

@ -214,6 +214,9 @@ func (s *NeighborsStore) GetNeighborsAt(
ctx context.Context,
sourceID string,
) (api.Neighbors, error) {
if !s.IsInitialized(sourceID) {
return nil, ErrSourceNotInitialized
}
if s.forceNeighborRefresh {
src := s.sources.GetInstance(sourceID)
if src == nil {
@ -231,6 +234,9 @@ func (s *NeighborsStore) GetNeighborsMapAt(
ctx context.Context,
sourceID string,
) (map[string]*api.Neighbor, error) {
if !s.IsInitialized(sourceID) {
return nil, ErrSourceNotInitialized
}
return s.backend.GetNeighborsMapAt(ctx, sourceID)
}
@ -279,7 +285,9 @@ func (s *NeighborsStore) LookupNeighbors(
results := make(api.NeighborsLookupResults)
for _, sourceID := range s.sources.GetSourceIDs() {
neighbors, err := s.lookupNeighborsAt(ctx, sourceID, query)
if err != nil {
if errors.Is(err, sources.ErrSourceNotFound) {
continue // Skip neighbors from this source for now
} else if err != nil {
return nil, err
}
results[sourceID] = neighbors
@ -341,6 +349,31 @@ func (s *NeighborsStore) Stats(
return storeStats
}
// Status returns the stores current status
func (s *NeighborsStore) Status(ctx context.Context) *api.StoreStatus {
initialized := true
sources := s.sources.GetSourcesStatus()
status := make(map[string]*api.SourceStatus)
for _, s := range sources {
if !s.Initialized {
initialized = false
}
status[s.SourceID] = &api.SourceStatus{
RefreshInterval: s.RefreshInterval,
LastRefresh: s.LastRefresh,
State: s.State.String(),
Initialized: s.Initialized,
}
}
meta := &api.StoreStatus{
Initialized: initialized,
Sources: status,
}
return meta
}
// SourceCachedAt returns the last time the store content
// was refreshed.
func (s *NeighborsStore) SourceCachedAt(sourceID string) time.Time {

View File

@ -218,6 +218,31 @@ func (s *RoutesStore) awaitNeighborStore(
}
}
// Status returns the store status meta
func (s *RoutesStore) Status(ctx context.Context) *api.StoreStatus {
initialized := true
sources := s.sources.GetSourcesStatus()
status := make(map[string]*api.SourceStatus)
for _, s := range sources {
if !s.Initialized {
initialized = false
}
status[s.SourceID] = &api.SourceStatus{
RefreshInterval: s.RefreshInterval,
LastRefresh: s.LastRefresh,
State: s.State.String(),
Initialized: s.Initialized,
}
}
meta := &api.StoreStatus{
Initialized: initialized,
Sources: status,
}
return meta
}
// Stats calculates some store insights
func (s *RoutesStore) Stats(ctx context.Context) *api.RoutesStoreStats {
totalImported := uint(0)

View File

@ -2,6 +2,7 @@ package store
import (
"context"
"errors"
"log"
"sort"
"sync"
@ -11,6 +12,11 @@ import (
"github.com/alice-lg/alice-lg/pkg/sources"
)
// ErrSourceNotInitialized is returned if a source
// is known but not yet initialized
var ErrSourceNotInitialized = errors.New(
"source is not initialized")
// Store State Constants
const (
StateInit = iota
@ -39,14 +45,14 @@ func (s State) String() string {
// Status defines a status the store can be in.
type Status struct {
RefreshInterval time.Duration
RefreshParallelism int
LastRefresh time.Time
LastRefreshDuration time.Duration
LastError interface{}
State State
Initialized bool
SourceID string
RefreshInterval time.Duration `json:"refresh_interval"`
RefreshParallelism int `json:"-"`
LastRefresh time.Time `json:"last_refresh"`
LastRefreshDuration time.Duration `json:"-"`
LastError interface{} `json:"-"`
State State `json:"state"`
Initialized bool `json:"initialized"`
SourceID string `json:"source_id"`
lastRefreshStart time.Time
}
@ -106,6 +112,18 @@ func NewSourcesStore(
}
}
// GetSourcesStatus will retrieve the status for all sources
// as a list.
func (s *SourcesStore) GetSourcesStatus() []*Status {
s.Lock()
defer s.Unlock()
status := []*Status{}
for _, s := range s.status {
status = append(status, s)
}
return status
}
// GetStatus will retrieve the status of a source
func (s *SourcesStore) GetStatus(sourceID string) (*Status, error) {
s.Lock()