Initial QSfera import
This commit is contained in:
+224
@@ -0,0 +1,224 @@
|
||||
// Copyright 2016 The OPA Authors. All rights reserved.
|
||||
// Use of this source code is governed by an Apache2
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package topdown
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
|
||||
"github.com/open-policy-agent/opa/v1/ast"
|
||||
"github.com/open-policy-agent/opa/v1/metrics"
|
||||
"github.com/open-policy-agent/opa/v1/topdown/builtins"
|
||||
"github.com/open-policy-agent/opa/v1/topdown/cache"
|
||||
"github.com/open-policy-agent/opa/v1/topdown/print"
|
||||
"github.com/open-policy-agent/opa/v1/tracing"
|
||||
)
|
||||
|
||||
type (
|
||||
// Deprecated: Functional-style builtins are deprecated. Use BuiltinFunc instead.
|
||||
FunctionalBuiltin1 func(op1 ast.Value) (output ast.Value, err error)
|
||||
|
||||
// Deprecated: Functional-style builtins are deprecated. Use BuiltinFunc instead.
|
||||
FunctionalBuiltin2 func(op1, op2 ast.Value) (output ast.Value, err error)
|
||||
|
||||
// Deprecated: Functional-style builtins are deprecated. Use BuiltinFunc instead.
|
||||
FunctionalBuiltin3 func(op1, op2, op3 ast.Value) (output ast.Value, err error)
|
||||
|
||||
// Deprecated: Functional-style builtins are deprecated. Use BuiltinFunc instead.
|
||||
FunctionalBuiltin4 func(op1, op2, op3, op4 ast.Value) (output ast.Value, err error)
|
||||
|
||||
// BuiltinContext contains context from the evaluator that may be used by
|
||||
// built-in functions.
|
||||
BuiltinContext struct {
|
||||
Context context.Context // request context that was passed when query started
|
||||
Metrics metrics.Metrics // metrics registry for recording built-in specific metrics
|
||||
Seed io.Reader // randomization source
|
||||
Time *ast.Term // wall clock time
|
||||
Cancel Cancel // atomic value that signals evaluation to halt
|
||||
Runtime *ast.Term // runtime information on the OPA instance
|
||||
Cache builtins.Cache // built-in function state cache
|
||||
InterQueryBuiltinCache cache.InterQueryCache // cross-query built-in function state cache
|
||||
InterQueryBuiltinValueCache cache.InterQueryValueCache // cross-query built-in function state value cache. this cache is useful for scenarios where the entry size cannot be calculated
|
||||
NDBuiltinCache builtins.NDBCache // cache for non-deterministic built-in state
|
||||
Location *ast.Location // location of built-in call
|
||||
Tracers []Tracer // Deprecated: Use QueryTracers instead
|
||||
QueryTracers []QueryTracer // tracer objects for trace() built-in function
|
||||
TraceEnabled bool // indicates whether tracing is enabled for the evaluation
|
||||
QueryID uint64 // identifies query being evaluated
|
||||
ParentID uint64 // identifies parent of query being evaluated
|
||||
PrintHook print.Hook // provides callback function to use for printing
|
||||
RoundTripper CustomizeRoundTripper // customize transport to use for HTTP requests
|
||||
DistributedTracingOpts tracing.Options // options to be used by distributed tracing.
|
||||
rand *rand.Rand // randomization source for non-security-sensitive operations
|
||||
Capabilities *ast.Capabilities
|
||||
}
|
||||
|
||||
// BuiltinFunc defines an interface for implementing built-in functions.
|
||||
// The built-in function is called with the plugged operands from the call
|
||||
// (including the output operands.) The implementation should evaluate the
|
||||
// operands and invoke the iterator for each successful/defined output
|
||||
// value.
|
||||
BuiltinFunc func(bctx BuiltinContext, operands []*ast.Term, iter func(*ast.Term) error) error
|
||||
)
|
||||
|
||||
// Rand returns a random number generator based on the Seed for this built-in
|
||||
// context. The random number will be re-used across multiple calls to this
|
||||
// function. If a random number generator cannot be created, an error is
|
||||
// returned.
|
||||
func (bctx *BuiltinContext) Rand() (*rand.Rand, error) {
|
||||
|
||||
if bctx.rand != nil {
|
||||
return bctx.rand, nil
|
||||
}
|
||||
|
||||
seed, err := readInt64(bctx.Seed)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
bctx.rand = rand.New(rand.NewSource(seed))
|
||||
return bctx.rand, nil
|
||||
}
|
||||
|
||||
// RegisterBuiltinFunc adds a new built-in function to the evaluation engine.
|
||||
func RegisterBuiltinFunc(name string, f BuiltinFunc) {
|
||||
builtinFunctions[name] = builtinErrorWrapper(name, f)
|
||||
}
|
||||
|
||||
// Deprecated: Functional-style builtins are deprecated. Use RegisterBuiltinFunc instead.
|
||||
func RegisterFunctionalBuiltin1(name string, fun FunctionalBuiltin1) {
|
||||
builtinFunctions[name] = functionalWrapper1(name, fun)
|
||||
}
|
||||
|
||||
// Deprecated: Functional-style builtins are deprecated. Use RegisterBuiltinFunc instead.
|
||||
func RegisterFunctionalBuiltin2(name string, fun FunctionalBuiltin2) {
|
||||
builtinFunctions[name] = functionalWrapper2(name, fun)
|
||||
}
|
||||
|
||||
// Deprecated: Functional-style builtins are deprecated. Use RegisterBuiltinFunc instead.
|
||||
func RegisterFunctionalBuiltin3(name string, fun FunctionalBuiltin3) {
|
||||
builtinFunctions[name] = functionalWrapper3(name, fun)
|
||||
}
|
||||
|
||||
// Deprecated: Functional-style builtins are deprecated. Use RegisterBuiltinFunc instead.
|
||||
func RegisterFunctionalBuiltin4(name string, fun FunctionalBuiltin4) {
|
||||
builtinFunctions[name] = functionalWrapper4(name, fun)
|
||||
}
|
||||
|
||||
// GetBuiltin returns a built-in function implementation, nil if no built-in found.
|
||||
func GetBuiltin(name string) BuiltinFunc {
|
||||
return builtinFunctions[name]
|
||||
}
|
||||
|
||||
// Deprecated: The BuiltinEmpty type is no longer needed. Use nil return values instead.
|
||||
type BuiltinEmpty struct{}
|
||||
|
||||
func (BuiltinEmpty) Error() string {
|
||||
return "<empty>"
|
||||
}
|
||||
|
||||
var builtinFunctions = map[string]BuiltinFunc{}
|
||||
|
||||
func builtinErrorWrapper(name string, fn BuiltinFunc) BuiltinFunc {
|
||||
return func(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error {
|
||||
err := fn(bctx, args, iter)
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
return handleBuiltinErr(name, bctx.Location, err)
|
||||
}
|
||||
}
|
||||
|
||||
func functionalWrapper1(name string, fn FunctionalBuiltin1) BuiltinFunc {
|
||||
return func(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error {
|
||||
result, err := fn(args[0].Value)
|
||||
if err == nil {
|
||||
return iter(ast.NewTerm(result))
|
||||
}
|
||||
return handleBuiltinErr(name, bctx.Location, err)
|
||||
}
|
||||
}
|
||||
|
||||
func functionalWrapper2(name string, fn FunctionalBuiltin2) BuiltinFunc {
|
||||
return func(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error {
|
||||
result, err := fn(args[0].Value, args[1].Value)
|
||||
if err == nil {
|
||||
return iter(ast.NewTerm(result))
|
||||
}
|
||||
return handleBuiltinErr(name, bctx.Location, err)
|
||||
}
|
||||
}
|
||||
|
||||
func functionalWrapper3(name string, fn FunctionalBuiltin3) BuiltinFunc {
|
||||
return func(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error {
|
||||
result, err := fn(args[0].Value, args[1].Value, args[2].Value)
|
||||
if err == nil {
|
||||
return iter(ast.NewTerm(result))
|
||||
}
|
||||
return handleBuiltinErr(name, bctx.Location, err)
|
||||
}
|
||||
}
|
||||
|
||||
func functionalWrapper4(name string, fn FunctionalBuiltin4) BuiltinFunc {
|
||||
return func(bctx BuiltinContext, args []*ast.Term, iter func(*ast.Term) error) error {
|
||||
result, err := fn(args[0].Value, args[1].Value, args[2].Value, args[3].Value)
|
||||
if err == nil {
|
||||
return iter(ast.NewTerm(result))
|
||||
}
|
||||
if _, empty := err.(BuiltinEmpty); empty {
|
||||
return nil
|
||||
}
|
||||
return handleBuiltinErr(name, bctx.Location, err)
|
||||
}
|
||||
}
|
||||
|
||||
func handleBuiltinErr(name string, loc *ast.Location, err error) error {
|
||||
switch err := err.(type) {
|
||||
case BuiltinEmpty:
|
||||
return nil
|
||||
case *Error, Halt:
|
||||
return err
|
||||
case builtins.ErrOperand:
|
||||
e := &Error{
|
||||
Code: TypeErr,
|
||||
Message: fmt.Sprintf("%v: %v", name, err.Error()),
|
||||
Location: loc,
|
||||
}
|
||||
return e.Wrap(err)
|
||||
default:
|
||||
e := &Error{
|
||||
Code: BuiltinErr,
|
||||
Message: fmt.Sprintf("%v: %v", name, err.Error()),
|
||||
Location: loc,
|
||||
}
|
||||
return e.Wrap(err)
|
||||
}
|
||||
}
|
||||
|
||||
func readInt64(r io.Reader) (int64, error) {
|
||||
bs := make([]byte, 8)
|
||||
n, err := io.ReadFull(r, bs)
|
||||
if n != len(bs) || err != nil {
|
||||
return 0, err
|
||||
}
|
||||
return int64(binary.BigEndian.Uint64(bs)), nil
|
||||
}
|
||||
|
||||
// Used to get older-style (ast.Term, error) tuples out of newer functions.
|
||||
func getResult(fn BuiltinFunc, operands ...*ast.Term) (*ast.Term, error) {
|
||||
var result *ast.Term
|
||||
extractionFn := func(r *ast.Term) error {
|
||||
result = r
|
||||
return nil
|
||||
}
|
||||
err := fn(BuiltinContext{}, operands, extractionFn)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
Reference in New Issue
Block a user