Documentation
¶
Overview ¶
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
- type BuiltinContext
- type BuiltinEmpty
- type BuiltinFunc
- type Cancel
- type Error
- type Event
- type FunctionalBuiltin1
- type FunctionalBuiltin2
- type FunctionalBuiltin3
- type FunctionalBuiltinVoid1
- type Op
- type 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" )
Variables ¶
This section is empty.
Functions ¶
func PrettyTrace ¶ added in v0.2.0
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 ¶ added in v0.4.0
func RegisterFunctionalBuiltin1(name string, fun FunctionalBuiltin1)
RegisterFunctionalBuiltin1 adds a new built-in function to the evaluation engine.
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.
}
Output: x: "CUSTOM"
func RegisterFunctionalBuiltin2 ¶ added in v0.4.0
func RegisterFunctionalBuiltin2(name string, fun FunctionalBuiltin2)
RegisterFunctionalBuiltin2 adds a new built-in function to the evaluation engine.
func RegisterFunctionalBuiltin3 ¶ added in v0.4.0
func RegisterFunctionalBuiltin3(name string, fun FunctionalBuiltin3)
RegisterFunctionalBuiltin3 adds a new built-in function to the evaluation engine.
func RegisterFunctionalBuiltinVoid1 ¶ added in v0.5.0
func RegisterFunctionalBuiltinVoid1(name string, fun FunctionalBuiltinVoid1)
RegisterFunctionalBuiltinVoid1 adds a new built-in function to the evaluation engine.
Types ¶
type BufferTracer ¶ added in v0.2.0
type BufferTracer []*Event
BufferTracer implements the Tracer interface by simply buffering all events received.
func NewBufferTracer ¶ added in v0.2.0
func NewBufferTracer() *BufferTracer
NewBufferTracer returns a new BufferTracer.
func (*BufferTracer) Enabled ¶ added in v0.2.0
func (b *BufferTracer) Enabled() bool
Enabled always returns true if the BufferTracer is instantiated.
func (*BufferTracer) Trace ¶ added in v0.2.0
func (b *BufferTracer) Trace(evt *Event)
Trace adds the event to the buffer.
type BuiltinContext ¶ added in v0.5.11
BuiltinContext contains context from the evaluator that may be used by built-in functions.
type BuiltinEmpty ¶ added in v0.4.0
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 ¶ added in v0.4.0
func (BuiltinEmpty) Error() string
type BuiltinFunc ¶
BuiltinFunc defines a generic interface for built-in functions.
type Cancel ¶ added in v0.5.1
type Cancel interface {
Cancel()
Cancelled() bool
}
Cancel defines the interface for cancelling topdown queries. Cancel operations are thread-safe and idempotent.
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.
type Event ¶ added in v0.2.0
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.
type FunctionalBuiltin1 ¶ added in v0.4.0
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 ¶ added in v0.4.0
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 ¶ added in v0.4.0
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 ¶ added in v0.5.0
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 ¶ added in v0.2.0
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 (*Query) Iter ¶ added in v0.5.11
Iter executes the query and invokes the iter function with query results produced by evaluating the query.
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)
}
Output: result: [2 3 4] err: <nil>
func (*Query) PartialIter ¶ added in v0.5.11
PartialIter executes the query invokes the iter function with partially evaluated queries produced by evaluating the query with a partial set.
func (*Query) PartialRun ¶ added in v0.5.11
PartialRun is a wrapper around PartialIter that accumulates results and returns them in one shot.
func (*Query) Run ¶ added in v0.5.11
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 ¶ added in v0.5.11
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 ¶ added in v0.5.11
WithCompiler sets the compiler to use for the query.
func (*Query) WithInput ¶ added in v0.5.11
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 ¶ added in v0.5.11
WithMetrics sets the metrics collection to add evaluation metrics to. This is optional.
func (*Query) WithPartial ¶ added in v0.5.11
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) WithTracer ¶ added in v0.5.11
WithTracer sets the query tracer to use during evaluation. This is optional.
func (*Query) WithTransaction ¶ added in v0.5.11
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 ¶ added in v0.2.1
QueryResult represents a single result returned by a query. The result contains bindings for all variables that appear in the query.
type QueryResultSet ¶ added in v0.2.1
type QueryResultSet []QueryResult
QueryResultSet represents a collection of results returned by a query.