mirror of
https://github.com/status-im/consul.git
synced 2025-01-09 21:35:52 +00:00
afa1cc98d1
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.
132 lines
2.7 KiB
Go
132 lines
2.7 KiB
Go
package bexpr
|
|
|
|
import (
|
|
"fmt"
|
|
"io"
|
|
"strings"
|
|
)
|
|
|
|
// TODO - Probably should make most of what is in here un-exported
|
|
|
|
//go:generate pigeon -o grammar.go -optimize-parser grammar.peg
|
|
//go:generate goimports -w grammar.go
|
|
|
|
type Expression interface {
|
|
ExpressionDump(w io.Writer, indent string, level int)
|
|
}
|
|
|
|
type UnaryOperator int
|
|
|
|
const (
|
|
UnaryOpNot UnaryOperator = iota
|
|
)
|
|
|
|
func (op UnaryOperator) String() string {
|
|
switch op {
|
|
case UnaryOpNot:
|
|
return "Not"
|
|
default:
|
|
return "UNKNOWN"
|
|
}
|
|
}
|
|
|
|
type BinaryOperator int
|
|
|
|
const (
|
|
BinaryOpAnd BinaryOperator = iota
|
|
BinaryOpOr
|
|
)
|
|
|
|
func (op BinaryOperator) String() string {
|
|
switch op {
|
|
case BinaryOpAnd:
|
|
return "And"
|
|
case BinaryOpOr:
|
|
return "Or"
|
|
default:
|
|
return "UNKNOWN"
|
|
}
|
|
}
|
|
|
|
type MatchOperator int
|
|
|
|
const (
|
|
MatchEqual MatchOperator = iota
|
|
MatchNotEqual
|
|
MatchIn
|
|
MatchNotIn
|
|
MatchIsEmpty
|
|
MatchIsNotEmpty
|
|
)
|
|
|
|
func (op MatchOperator) String() string {
|
|
switch op {
|
|
case MatchEqual:
|
|
return "Equal"
|
|
case MatchNotEqual:
|
|
return "Not Equal"
|
|
case MatchIn:
|
|
return "In"
|
|
case MatchNotIn:
|
|
return "Not In"
|
|
case MatchIsEmpty:
|
|
return "Is Empty"
|
|
case MatchIsNotEmpty:
|
|
return "Is Not Empty"
|
|
default:
|
|
return "UNKNOWN"
|
|
}
|
|
}
|
|
|
|
type MatchValue struct {
|
|
Raw string
|
|
Converted interface{}
|
|
}
|
|
|
|
type UnaryExpression struct {
|
|
Operator UnaryOperator
|
|
Operand Expression
|
|
}
|
|
|
|
type BinaryExpression struct {
|
|
Left Expression
|
|
Operator BinaryOperator
|
|
Right Expression
|
|
}
|
|
|
|
type Selector []string
|
|
|
|
func (sel Selector) String() string {
|
|
return strings.Join([]string(sel), ".")
|
|
}
|
|
|
|
type MatchExpression struct {
|
|
Selector Selector
|
|
Operator MatchOperator
|
|
Value *MatchValue
|
|
}
|
|
|
|
func (expr *UnaryExpression) ExpressionDump(w io.Writer, indent string, level int) {
|
|
localIndent := strings.Repeat(indent, level)
|
|
fmt.Fprintf(w, "%s%s {\n", localIndent, expr.Operator.String())
|
|
expr.Operand.ExpressionDump(w, indent, level+1)
|
|
fmt.Fprintf(w, "%s}\n", localIndent)
|
|
}
|
|
|
|
func (expr *BinaryExpression) ExpressionDump(w io.Writer, indent string, level int) {
|
|
localIndent := strings.Repeat(indent, level)
|
|
fmt.Fprintf(w, "%s%s {\n", localIndent, expr.Operator.String())
|
|
expr.Left.ExpressionDump(w, indent, level+1)
|
|
expr.Right.ExpressionDump(w, indent, level+1)
|
|
fmt.Fprintf(w, "%s}\n", localIndent)
|
|
}
|
|
|
|
func (expr *MatchExpression) ExpressionDump(w io.Writer, indent string, level int) {
|
|
switch expr.Operator {
|
|
case MatchEqual, MatchNotEqual, MatchIn, MatchNotIn:
|
|
fmt.Fprintf(w, "%[1]s%[3]s {\n%[2]sSelector: %[4]v\n%[2]sValue: %[5]q\n%[1]s}\n", strings.Repeat(indent, level), strings.Repeat(indent, level+1), expr.Operator.String(), expr.Selector, expr.Value.Raw)
|
|
default:
|
|
fmt.Fprintf(w, "%[1]s%[3]s {\n%[2]sSelector: %[4]v\n%[1]s}\n", strings.Repeat(indent, level), strings.Repeat(indent, level+1), expr.Operator.String(), expr.Selector)
|
|
}
|
|
}
|