package topdown
import "github.com/open-policy-agent/opa/topdown"
Package topdown provides low-level query evaluation support.
The topdown implementation is a modified version of the standard top-down evaluation algorithm used in Datalog. References and comprehensions are evaluated eagerly while all other terms are evaluated lazily.
Index ¶
- Constants
- func IsCancel(err error) bool
- func IsError(err error) bool
- func PrettyTrace(w io.Writer, trace []*Event)
- func RegisterBuiltinFunc(name string, f BuiltinFunc)
- func RegisterFunctionalBuiltin1(name string, fun FunctionalBuiltin1)
- func RegisterFunctionalBuiltin2(name string, fun FunctionalBuiltin2)
- func RegisterFunctionalBuiltin3(name string, fun FunctionalBuiltin3)
- func RegisterFunctionalBuiltinVoid1(name string, fun FunctionalBuiltinVoid1)
- type BufferTracer
- func NewBufferTracer() *BufferTracer
- func (b *BufferTracer) Enabled() bool
- func (b *BufferTracer) Trace(evt *Event)
- type BuiltinContext
- type BuiltinEmpty
- type BuiltinFunc
- type Cancel
- type Error
- type Event
- func (evt *Event) Equal(other *Event) bool
- func (evt *Event) HasBody() bool
- func (evt *Event) HasExpr() bool
- func (evt *Event) HasRule() bool
- func (evt *Event) String() string
- type FunctionalBuiltin1
- type FunctionalBuiltin2
- type FunctionalBuiltin3
- type FunctionalBuiltinVoid1
- type Op
- type Query
- func NewQuery(query ast.Body) *Query
- func (q *Query) Iter(ctx context.Context, iter func(QueryResult) error) error
- func (q *Query) PartialIter(ctx context.Context, iter func(ast.Body) error) error
- func (q *Query) PartialRun(ctx context.Context) ([]ast.Body, error)
- func (q *Query) Run(ctx context.Context) (QueryResultSet, error)
- func (q *Query) WithCancel(cancel Cancel) *Query
- func (q *Query) WithCompiler(compiler *ast.Compiler) *Query
- func (q *Query) WithInput(input *ast.Term) *Query
- func (q *Query) WithMetrics(metrics metrics.Metrics) *Query
- func (q *Query) WithPartial(terms []*ast.Term) *Query
- func (q *Query) WithStore(store storage.Store) *Query
- func (q *Query) WithTracer(tracer Tracer) *Query
- func (q *Query) WithTransaction(txn storage.Transaction) *Query
- type QueryResult
- type QueryResultSet
- type Tracer
Examples ¶
Constants ¶
const ( // InternalErr represents an unknown evaluation error. InternalErr string = "eval_internal_error" // CancelErr indicates the evaluation process was cancelled. CancelErr string = "eval_cancel_error" // ConflictErr indicates a conflict was encountered during evaluation. For // instance, a conflict occurs if a rule produces multiple, differing values // for the same key in an object. Conflict errors indicate the policy does // not account for the data loaded into the policy engine. ConflictErr string = "eval_conflict_error" // TypeErr indicates evaluation stopped because an expression was applied to // a value of an inappropriate type. TypeErr string = "eval_type_error" )
Functions ¶
func IsCancel ¶
IsCancel returns true if err was caused by cancellation.
func IsError ¶
IsError returns true if the err is an Error.
func PrettyTrace ¶
PrettyTrace pretty prints the trace to the writer.
func RegisterBuiltinFunc ¶
func RegisterBuiltinFunc(name string, f BuiltinFunc)
RegisterBuiltinFunc adds a new built-in function to the evaluation engine.
func RegisterFunctionalBuiltin1 ¶
func RegisterFunctionalBuiltin1(name string, fun FunctionalBuiltin1)
RegisterFunctionalBuiltin1 adds a new built-in function to the evaluation
engine.
Code:play
Output:Example¶
package main
import (
"context"
"fmt"
"strings"
"github.com/open-policy-agent/opa/ast"
"github.com/open-policy-agent/opa/topdown"
"github.com/open-policy-agent/opa/topdown/builtins"
"github.com/open-policy-agent/opa/types"
)
func main() {
// Rego includes a number of built-in functions ("built-ins") for performing
// standard operations like string manipulation, regular expression
// matching, and computing aggregates.
//
// This test shows how to add a new built-in to Rego and OPA.
// Initialize context for the example. Normally the caller would obtain the
// context from an input parameter or instantiate their own.
ctx := context.Background()
// The ast package contains a registry that enumerates the built-ins
// included in Rego. When adding a new built-in, you must update the
// registry to include your built-in. Otherwise, the compiler will complain
// when it encounters your built-in.
builtin := &ast.Builtin{
Name: "mybuiltins.upper",
Decl: types.NewFunction(
types.Args(types.S),
types.S,
),
}
ast.RegisterBuiltin(builtin)
// This is the implementation of the built-in that will be called during
// query evaluation.
builtinImpl := func(a ast.Value) (ast.Value, error) {
str, err := builtins.StringOperand(a, 1)
if err != nil {
return nil, err
}
if str.Equal(ast.String("magic")) {
// topdown.BuiltinEmpty indicates to the evaluation engine that the
// expression is false/not defined.
return nil, topdown.BuiltinEmpty{}
}
return ast.String(strings.ToUpper(string(str))), nil
}
// See documentation for registering functions that take different numbers
// of arguments.
topdown.RegisterFunctionalBuiltin1(builtin.Name, builtinImpl)
// At this point, the new built-in has been registered and can be used in
// queries. Our custom built-in converts strings to upper case but is not
// defined for the input "magic".
compiler := ast.NewCompiler()
query, err := compiler.QueryCompiler().Compile(ast.MustParseBody(`mybuiltins.upper("custom", x); not mybuiltins.upper("magic", "MAGIC")`))
if err != nil {
// Handle error.
}
// Evaluate the query.
q := topdown.NewQuery(query).WithCompiler(compiler)
q.Iter(ctx, func(qr topdown.QueryResult) error {
fmt.Println("x:", qr[ast.Var("x")])
return nil
})
// If you add a new built-in function to OPA, you should:
//
// 1. Update the Language Reference: http://www.openpolicyagent.org/docs/language-reference.html.
// 2. Add an integration test to the topdown package.
}
x: "CUSTOM"
func RegisterFunctionalBuiltin2 ¶
func RegisterFunctionalBuiltin2(name string, fun FunctionalBuiltin2)
RegisterFunctionalBuiltin2 adds a new built-in function to the evaluation engine.
func RegisterFunctionalBuiltin3 ¶
func RegisterFunctionalBuiltin3(name string, fun FunctionalBuiltin3)
RegisterFunctionalBuiltin3 adds a new built-in function to the evaluation engine.
func RegisterFunctionalBuiltinVoid1 ¶
func RegisterFunctionalBuiltinVoid1(name string, fun FunctionalBuiltinVoid1)
RegisterFunctionalBuiltinVoid1 adds a new built-in function to the evaluation engine.
Types ¶
type BufferTracer ¶
type BufferTracer []*Event
BufferTracer implements the Tracer interface by simply buffering all events received.
func NewBufferTracer ¶
func NewBufferTracer() *BufferTracer
NewBufferTracer returns a new BufferTracer.
func (*BufferTracer) Enabled ¶
func (b *BufferTracer) Enabled() bool
Enabled always returns true if the BufferTracer is instantiated.
func (*BufferTracer) Trace ¶
func (b *BufferTracer) Trace(evt *Event)
Trace adds the event to the buffer.
type BuiltinContext ¶
BuiltinContext contains context from the evaluator that may be used by built-in functions.
type BuiltinEmpty ¶
type BuiltinEmpty struct{}
BuiltinEmpty is used to signal that the built-in function evaluated, but the result is undefined so evaluation should not continue.
func (BuiltinEmpty) Error ¶
func (BuiltinEmpty) Error() string
type BuiltinFunc ¶
BuiltinFunc defines a generic interface for built-in functions.
type Cancel ¶
type Cancel interface { Cancel() Cancelled() bool }
Cancel defines the interface for cancelling topdown queries. Cancel operations are thread-safe and idempotent.
func NewCancel ¶
func NewCancel() Cancel
NewCancel returns a new Cancel object.
type Error ¶
type Error struct { Code string `json:"code"` Message string `json:"message"` Location *ast.Location `json:"location,omitempty"` }
Error is the error type returned by the Eval and Query functions when an evaluation error occurs.
func (*Error) Error ¶
type Event ¶
type Event struct { Op Op // Identifies type of event. Node interface{} // Contains AST node relevant to the event. QueryID uint64 // Identifies the query this event belongs to. ParentID uint64 // Identifies the parent query this event belongs to. Locals *ast.ValueMap // Contains local variable bindings from the query context. }
Event contains state associated with a tracing event.
func (*Event) Equal ¶
Equal returns true if this event is equal to the other event.
func (*Event) HasBody ¶
HasBody returns true if the Event contains an ast.Body.
func (*Event) HasExpr ¶
HasExpr returns true if the Event contains an ast.Expr.
func (*Event) HasRule ¶
HasRule returns true if the Event contains an ast.Rule.
func (*Event) String ¶
type FunctionalBuiltin1 ¶
FunctionalBuiltin1 defines an interface for simple functional built-ins.
Implement this interface if your built-in function takes one input and produces one output.
If an error occurs, the functional built-in should return a descriptive message. The message should not be prefixed with the built-in name as the framework takes care of this.
type FunctionalBuiltin2 ¶
FunctionalBuiltin2 defines an interface for simple functional built-ins.
Implement this interface if your built-in function takes two inputs and produces one output.
If an error occurs, the functional built-in should return a descriptive message. The message should not be prefixed with the built-in name as the framework takes care of this.
type FunctionalBuiltin3 ¶
FunctionalBuiltin3 defines an interface for simple functional built-ins.
Implement this interface if your built-in function takes three inputs and produces one output.
If an error occurs, the functional built-in should return a descriptive message. The message should not be prefixed with the built-in name as the framework takes care of this.
type FunctionalBuiltinVoid1 ¶
FunctionalBuiltinVoid1 defines an interface for simple functional built-ins.
Implement this interface if your built-in function takes one input and produces no outputs.
If an error occurs, the functional built-in should return a descriptive message. The message should not be prefixed with the built-in name as the framework takes care of this.
type Op ¶
type Op string
Op defines the types of tracing events.
const ( // EnterOp is emitted when a new query is about to be evaluated. EnterOp Op = "Enter" // ExitOp is emitted when a query has evaluated to true. ExitOp Op = "Exit" // EvalOp is emitted when an expression is about to be evaluated. EvalOp Op = "Eval" // RedoOp is emitted when an expression, rule, or query is being re-evaluated. RedoOp Op = "Redo" // FailOp is emitted when an expression evaluates to false. FailOp Op = "Fail" )
type Query ¶
type Query struct {
// contains filtered or unexported fields
}
Query provides a configurable interface for performing query evaluation.
func NewQuery ¶
NewQuery returns a new Query object that can be run.
func (*Query) Iter ¶
Iter executes the query and invokes the iter function with query results
produced by evaluating the query.
Code:play
Output:Example¶
package main
import (
"bytes"
"context"
"encoding/json"
"fmt"
"github.com/open-policy-agent/opa/ast"
"github.com/open-policy-agent/opa/storage/inmem"
"github.com/open-policy-agent/opa/topdown"
)
func main() {
// Initialize context for the example. Normally the caller would obtain the
// context from an input parameter or instantiate their own.
ctx := context.Background()
compiler := ast.NewCompiler()
// Define a dummy query and some data that the query will execute against.
query, err := compiler.QueryCompiler().Compile(ast.MustParseBody(`data.a[_] = x; x >= 2`))
if err != nil {
// Handle error.
}
var data map[string]interface{}
// OPA uses Go's standard JSON library but assumes that numbers have been
// decoded as json.Number instead of float64. You MUST decode with UseNumber
// enabled.
decoder := json.NewDecoder(bytes.NewBufferString(`{"a": [1,2,3,4]}`))
decoder.UseNumber()
if err := decoder.Decode(&data); err != nil {
// Handle error.
}
// Instantiate the policy engine's storage layer.
store := inmem.NewFromObject(data)
// Create a new transaction. Transactions allow the policy engine to
// evaluate the query over a consistent snapshot fo the storage layer.
txn, err := store.NewTransaction(ctx)
if err != nil {
// Handle error.
}
defer store.Abort(ctx, txn)
// Prepare the evaluation parameters. Evaluation executes against the policy
// engine's storage. In this case, we seed the storage with a single array
// of number. Other parameters such as the input, tracing configuration,
// etc. can be set on the query object.
q := topdown.NewQuery(query).
WithCompiler(compiler).
WithStore(store).
WithTransaction(txn)
result := []interface{}{}
// Execute the query and provide a callback function to accumulate the results.
err = q.Iter(ctx, func(qr topdown.QueryResult) error {
// Each variable in the query will have an associated binding.
x := qr[ast.Var("x")]
// The bindings are ast.Value types so we will convert to a native Go value here.
v, err := ast.JSON(x.Value)
if err != nil {
return err
}
result = append(result, v)
return nil
})
// Inspect the query result.
fmt.Println("result:", result)
fmt.Println("err:", err)
}
result: [2 3 4]
err: <nil>
func (*Query) PartialIter ¶
PartialIter executes the query invokes the iter function with partially evaluated queries produced by evaluating the query with a partial set.
func (*Query) PartialRun ¶
PartialRun is a wrapper around PartialIter that accumulates results and returns them in one shot.
func (*Query) Run ¶
func (q *Query) Run(ctx context.Context) (QueryResultSet, error)
Run is a wrapper around Iter that accumulates query results and returns them in one shot.
func (*Query) WithCancel ¶
WithCancel sets the cancellation object to use for the query. Set this if you need to abort queries based on a deadline. This is optional.
func (*Query) WithCompiler ¶
WithCompiler sets the compiler to use for the query.
func (*Query) WithInput ¶
WithInput sets the input object to use for the query. References rooted at input will be evaluated against this value. This is optional.
func (*Query) WithMetrics ¶
WithMetrics sets the metrics collection to add evaluation metrics to. This is optional.
func (*Query) WithPartial ¶
WithPartial sets the initial set of vars or refs to treat as unavailable during query evaluation. This is typically required for partial evaluation.
func (*Query) WithStore ¶
WithStore sets the store to use for the query.
func (*Query) WithTracer ¶
WithTracer sets the query tracer to use during evaluation. This is optional.
func (*Query) WithTransaction ¶
func (q *Query) WithTransaction(txn storage.Transaction) *Query
WithTransaction sets the transaction to use for the query. All queries should be performed over a consistent snapshot of the storage layer.
type QueryResult ¶
QueryResult represents a single result returned by a query. The result contains bindings for all variables that appear in the query.
type QueryResultSet ¶
type QueryResultSet []QueryResult
QueryResultSet represents a collection of results returned by a query.
type Tracer ¶
Tracer defines the interface for tracing in the top-down evaluation engine.
Source Files ¶
aggregates.go arithmetic.go binary.go bindings.go builtins.go cache.go cancel.go casts.go doc.go encoding.go errors.go eval.go ineq.go input.go partial.go query.go regex.go sets.go strings.go time.go tokens.go trace.go walk.go
Directories ¶
Path | Synopsis |
---|---|
topdown/builtins | Package builtins contains utilities for implementing built-in functions. |
- Version
- v0.5.12
- Published
- Nov 22, 2017
- Platform
- darwin/amd64
- Imports
- 21 packages
- Last checked
- 2 minutes ago –
Tools for package owners.