ac78c23021
Fixes: #4222 # Data Filtering This PR will implement filtering for the following endpoints: ## Supported HTTP Endpoints - `/agent/checks` - `/agent/services` - `/catalog/nodes` - `/catalog/service/:service` - `/catalog/connect/:service` - `/catalog/node/:node` - `/health/node/:node` - `/health/checks/:service` - `/health/service/:service` - `/health/connect/:service` - `/health/state/:state` - `/internal/ui/nodes` - `/internal/ui/services` More can be added going forward and any endpoint which is used to list some data is a good candidate. ## Usage When using the HTTP API a `filter` query parameter can be used to pass a filter expression to Consul. Filter Expressions take the general form of: ``` <selector> == <value> <selector> != <value> <value> in <selector> <value> not in <selector> <selector> contains <value> <selector> not contains <value> <selector> is empty <selector> is not empty not <other expression> <expression 1> and <expression 2> <expression 1> or <expression 2> ``` Normal boolean logic and precedence is supported. All of the actual filtering and evaluation logic is coming from the [go-bexpr](https://github.com/hashicorp/go-bexpr) library ## Other changes Adding the `Internal.ServiceDump` RPC endpoint. This will allow the UI to filter services better.
60 lines
1.2 KiB
Go
60 lines
1.2 KiB
Go
package bexpr
|
|
|
|
import (
|
|
"reflect"
|
|
"sync"
|
|
)
|
|
|
|
var DefaultRegistry Registry = NewSyncRegistry()
|
|
|
|
type Registry interface {
|
|
GetFieldConfigurations(reflect.Type) (FieldConfigurations, error)
|
|
}
|
|
|
|
type SyncRegistry struct {
|
|
configurations map[reflect.Type]FieldConfigurations
|
|
lock sync.RWMutex
|
|
}
|
|
|
|
func NewSyncRegistry() *SyncRegistry {
|
|
return &SyncRegistry{
|
|
configurations: make(map[reflect.Type]FieldConfigurations),
|
|
}
|
|
}
|
|
|
|
func (r *SyncRegistry) GetFieldConfigurations(rtype reflect.Type) (FieldConfigurations, error) {
|
|
if r != nil {
|
|
r.lock.RLock()
|
|
configurations, ok := r.configurations[rtype]
|
|
r.lock.RUnlock()
|
|
|
|
if ok {
|
|
return configurations, nil
|
|
}
|
|
}
|
|
|
|
fields, err := generateFieldConfigurations(rtype)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
if r != nil {
|
|
r.lock.Lock()
|
|
r.configurations[rtype] = fields
|
|
r.lock.Unlock()
|
|
}
|
|
|
|
return fields, nil
|
|
}
|
|
|
|
type nilRegistry struct{}
|
|
|
|
// The pass through registry can be used to prevent using the default registry and thus storing
|
|
// any field configurations
|
|
var NilRegistry = (*nilRegistry)(nil)
|
|
|
|
func (r *nilRegistry) GetFieldConfigurations(rtype reflect.Type) (FieldConfigurations, error) {
|
|
fields, err := generateFieldConfigurations(rtype)
|
|
return fields, err
|
|
}
|