Example #1
0
func setupBenchmark(nodes int, pods int) *topdown.QueryParams {

	// policy compilation
	c := ast.NewCompiler()
	modules := map[string]*ast.Module{
		"test": ast.MustParseModule(policy),
	}

	if c.Compile(modules); c.Failed() {
		panic(c.Errors)
	}

	// storage setup
	store := storage.New(storage.InMemoryConfig())

	// parameter setup
	ctx := context.Background()
	request := ast.ObjectTerm(ast.Item(ast.StringTerm("pod"), ast.MustParseTerm(requestedPod)))
	path := ast.MustParseRef("data.opa.test.scheduler.fit")
	txn := storage.NewTransactionOrDie(ctx, store)
	params := topdown.NewQueryParams(ctx, c, store, txn, request.Value, path)

	// data setup
	setupNodes(ctx, store, txn, nodes)
	setupRCs(ctx, store, txn, 1)
	setupPods(ctx, store, txn, pods, nodes)

	return params
}
Example #2
0
func setup(t *testing.T, filename string) *topdown.QueryParams {

	// policy compilation
	c := ast.NewCompiler()
	modules := map[string]*ast.Module{
		"test": ast.MustParseModule(policy),
	}

	if c.Compile(modules); c.Failed() {
		t.Fatal("unexpected error:", c.Errors)
	}

	// storage setup
	store := storage.New(storage.Config{
		Builtin: loadDataStore(filename),
	})

	// parameter setup
	ctx := context.Background()
	request := ast.ObjectTerm(ast.Item(ast.StringTerm("pod"), ast.MustParseTerm(requestedPod)))
	path := ast.MustParseRef("data.opa.test.scheduler.fit")
	txn := storage.NewTransactionOrDie(ctx, store)
	params := topdown.NewQueryParams(ctx, c, store, txn, request.Value, path)

	return params
}
Example #3
0
func ExampleQuery() {
	// 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 module with rules that produce documents that we will query below.
	module, err := ast.ParseModule("my_module.rego", `

	    package opa.example

	    p[x] :- q[x], not r[x]
	    q[y] :- a = [1,2,3], y = a[_]
	    r[z] :- b = [2,4], z = b[_]

	`)

	mods := map[string]*ast.Module{
		"my_module": module,
	}

	if compiler.Compile(mods); compiler.Failed() {
		fmt.Println(compiler.Errors)
	}

	if err != nil {
		// Handle error.
	}

	// Instantiate the policy engine's storage layer.
	store := storage.New(storage.InMemoryConfig())

	// 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.Close(ctx, txn)

	// Prepare query parameters. In this case, there are no additional documents
	// required by the policy so the request is nil.
	var request ast.Value
	params := topdown.NewQueryParams(ctx, compiler, store, txn, request, ast.MustParseRef("data.opa.example.p"))

	// Execute the query against "p".
	v1, err1 := topdown.Query(params)

	// Inspect the result.
	fmt.Println("v1:", v1[0].Result)
	fmt.Println("err1:", err1)

	// Output:
	// v1: [1 3]
	// err1: <nil>

}
Example #4
0
func newPolicy(id, s string) *policyV1 {
	compiler := ast.NewCompiler()
	parsed := ast.MustParseModule(s)
	if compiler.Compile(map[string]*ast.Module{"": parsed}); compiler.Failed() {
		panic(compiler.Errors)
	}
	mod := compiler.Modules[""]
	return &policyV1{ID: id, Module: mod}
}
Example #5
0
File: repl.go Project: tsandall/opa
func (r *REPL) cmdUnset(args []string) error {

	if len(args) != 1 {
		return newBadArgsErr("unset <var>: expects exactly one argument")
	}

	term, err := ast.ParseTerm(args[0])
	if err != nil {
		return newBadArgsErr("argument must identify a rule")
	}

	v, ok := term.Value.(ast.Var)
	if !ok {
		return newBadArgsErr("argument must identify a rule")
	}

	mod := r.modules[r.currentModuleID]
	rules := []*ast.Rule{}

	for _, r := range mod.Rules {
		if !r.Name.Equal(v) {
			rules = append(rules, r)
		}
	}

	if len(rules) == len(mod.Rules) {
		fmt.Fprintln(r.output, "warning: no matching rules in current module")
		return nil
	}

	cpy := mod.Copy()
	cpy.Rules = rules

	policies := r.store.ListPolicies(r.txn)
	policies[r.currentModuleID] = cpy

	for id, mod := range r.modules {
		if id != r.currentModuleID {
			policies[id] = mod
		}
	}

	compiler := ast.NewCompiler()

	if compiler.Compile(policies); compiler.Failed() {
		return compiler.Errors
	}

	r.modules[r.currentModuleID] = cpy

	return nil
}
Example #6
0
func (f *fixture) compile1(m string) *ast.Module {

	mods := f.policyStore.List()
	mod := ast.MustParseModule(m)
	mods[""] = mod

	c := ast.NewCompiler()
	if c.Compile(mods); c.Failed() {
		panic(c.Errors)
	}

	return c.Modules[""]
}
Example #7
0
func explainQuery(data string, module string) ([]*topdown.Event, []*topdown.Event, error) {

	compiler := ast.NewCompiler()
	mods := map[string]*ast.Module{"": ast.MustParseModule(module)}

	if compiler.Compile(mods); compiler.Failed() {
		panic(compiler.Errors)
	}

	buf := topdown.NewBufferTracer()
	executeQuery(data, compiler, buf)

	answer, err := Truth(compiler, *buf)
	return answer, *buf, err
}
Example #8
0
File: repl.go Project: tsandall/opa
func (r *REPL) loadCompiler() (*ast.Compiler, error) {

	policies := r.store.ListPolicies(r.txn)
	for id, mod := range r.modules {
		policies[id] = mod
	}

	compiler := ast.NewCompiler()

	if compiler.Compile(policies); compiler.Failed() {
		return nil, compiler.Errors
	}

	return compiler, nil
}
Example #9
0
// New returns a new Server.
func New(ctx context.Context, store *storage.Storage, addr string, persist bool) (*Server, error) {

	s := &Server{
		addr:    addr,
		persist: persist,
		store:   store,
	}

	// Initialize HTTP handlers.
	router := mux.NewRouter()
	s.registerHandlerV1(router, "/data/{path:.+}", "PUT", s.v1DataPut)
	s.registerHandlerV1(router, "/data", "PUT", s.v1DataPut)
	s.registerHandlerV1(router, "/data/{path:.+}", "GET", s.v1DataGet)
	s.registerHandlerV1(router, "/data", "GET", s.v1DataGet)
	s.registerHandlerV1(router, "/data/{path:.+}", "PATCH", s.v1DataPatch)
	s.registerHandlerV1(router, "/data", "PATCH", s.v1DataPatch)
	s.registerHandlerV1(router, "/policies", "GET", s.v1PoliciesList)
	s.registerHandlerV1(router, "/policies/{id}", "DELETE", s.v1PoliciesDelete)
	s.registerHandlerV1(router, "/policies/{id}", "GET", s.v1PoliciesGet)
	s.registerHandlerV1(router, "/policies/{id}/raw", "GET", s.v1PoliciesRawGet)
	s.registerHandlerV1(router, "/policies/{id}", "PUT", s.v1PoliciesPut)
	s.registerHandlerV1(router, "/query", "GET", s.v1QueryGet)
	router.HandleFunc("/", s.indexGet).Methods("GET")
	s.Handler = router

	// Initialize compiler with policies found in storage.
	txn, err := s.store.NewTransaction(ctx)
	if err != nil {
		return nil, err
	}

	defer s.store.Close(ctx, txn)

	modules := s.store.ListPolicies(txn)
	compiler := ast.NewCompiler()

	if compiler.Compile(modules); compiler.Failed() {
		return nil, compiler.Errors
	}

	s.setCompiler(compiler)

	return s, nil
}
Example #10
0
func ExampleCompiler_Compile() {

	// Define an input module that will be compiled.
	exampleModule := `

		package opa.example

		import data.foo
		import request.bar

		p[x] :- foo[x], not bar[x], x >= min_x

		min_x = 100

	`

	// Parse the input module to obtain the AST representation.
	mod, err := ast.ParseModule("my_module", exampleModule)
	if err != nil {
		fmt.Println("Parse error:", err)
	}

	// Create a new compiler instance and compile the module.
	c := ast.NewCompiler()

	mods := map[string]*ast.Module{
		"my_module": mod,
	}

	if c.Compile(mods); c.Failed() {
		fmt.Println("Compile error:", c.Errors)
	}

	fmt.Println("Expr 1:", c.Modules["my_module"].Rules[0].Body[0])
	fmt.Println("Expr 2:", c.Modules["my_module"].Rules[0].Body[1])
	fmt.Println("Expr 3:", c.Modules["my_module"].Rules[0].Body[2])

	// Output:
	//
	// Expr 1: data.foo[x]
	// Expr 2: not request.bar[x]
	// Expr 3: gte(x, data.opa.example.min_x)
}
Example #11
0
File: repl.go Project: tsandall/opa
func (r *REPL) compileBody(body ast.Body) (ast.Body, error) {

	policies := r.store.ListPolicies(r.txn)

	for id, mod := range r.modules {
		policies[id] = mod
	}

	compiler := ast.NewCompiler()

	if compiler.Compile(policies); compiler.Failed() {
		return nil, compiler.Errors
	}

	qctx := ast.NewQueryContextForModule(r.modules[r.currentModuleID])
	return compiler.QueryCompiler().
		WithContext(qctx).
		Compile(body)
}
Example #12
0
// loadPolicies is the default callback function that will be used when
// opening the policy store.
func loadPolicies(bufs map[string][]byte) (map[string]*ast.Module, error) {

	parsed := map[string]*ast.Module{}

	for id, bs := range bufs {
		mod, err := ast.ParseModule(id, string(bs))
		if err != nil {
			return nil, err
		}
		parsed[id] = mod
	}

	c := ast.NewCompiler()
	if c.Compile(parsed); c.Failed() {
		return nil, c.Errors
	}

	return parsed, nil
}
Example #13
0
File: repl.go Project: tsandall/opa
func (r *REPL) compileRule(rule *ast.Rule) error {

	mod := r.modules[r.currentModuleID]
	prev := mod.Rules
	mod.Rules = append(mod.Rules, rule)

	policies := r.store.ListPolicies(r.txn)
	for id, mod := range r.modules {
		policies[id] = mod
	}

	compiler := ast.NewCompiler()

	if compiler.Compile(policies); compiler.Failed() {
		mod.Rules = prev
		return compiler.Errors
	}

	return nil
}
Example #14
0
func TestPolicyStoreDefaultOpen(t *testing.T) {

	dir, err := ioutil.TempDir("", "policyDir")
	if err != nil {
		panic(err)
	}

	defer os.RemoveAll(dir)

	filename := filepath.Join(dir, "testMod1")

	err = ioutil.WriteFile(filename, []byte(testMod1), 0644)
	if err != nil {
		panic(err)
	}

	policyStore := newPolicyStore(dir)

	err = policyStore.Open(invalidTXN, loadPolicies)
	if err != nil {
		t.Errorf("Unexpected error on Open(): %v", err)
		return
	}

	c := ast.NewCompiler()
	mod := ast.MustParseModule(testMod1)
	if c.Compile(map[string]*ast.Module{"testMod1": mod}); c.Failed() {
		panic(c.Errors)
	}

	stored, err := policyStore.Get("testMod1")
	if err != nil {
		t.Errorf("Unexpected error on Get(): %v", err)
		return
	}

	if !mod.Equal(stored) {
		t.Fatalf("Expected %v from policy store but got: %v", mod, stored)
	}
}
Example #15
0
func compileAndStoreInputs(modules map[string]*loadedModule, store *storage.Storage, txn storage.Transaction) error {

	policies := store.ListPolicies(txn)

	for id, mod := range modules {
		policies[id] = mod.Parsed
	}

	c := ast.NewCompiler()

	if c.Compile(policies); c.Failed() {
		return c.Errors
	}

	for id := range modules {
		if err := store.InsertPolicy(txn, id, modules[id].Parsed, modules[id].Raw, false); err != nil {
			return err
		}
	}

	return nil
}
Example #16
0
func (s *Server) v1PoliciesDelete(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	vars := mux.Vars(r)
	id := vars["id"]

	txn, err := s.store.NewTransaction(ctx)
	if err != nil {
		handleErrorAuto(w, err)
		return
	}

	defer s.store.Close(ctx, txn)

	_, _, err = s.store.GetPolicy(txn, id)
	if err != nil {
		handleErrorAuto(w, err)
		return
	}

	mods := s.store.ListPolicies(txn)
	delete(mods, id)

	c := ast.NewCompiler()

	if c.Compile(mods); c.Failed() {
		handleErrorAST(w, 400, compileModErrMsg, c.Errors)
		return
	}

	if err := s.store.DeletePolicy(txn, id); err != nil {
		handleErrorAuto(w, err)
		return
	}

	s.setCompiler(c)

	handleResponse(w, 204, nil)
}
Example #17
0
func (s *Server) v1PoliciesPut(w http.ResponseWriter, r *http.Request) {
	ctx := r.Context()
	vars := mux.Vars(r)
	id := vars["id"]

	buf, err := ioutil.ReadAll(r.Body)
	if err != nil {
		handleError(w, 500, err)
		return
	}

	parsedMod, err := ast.ParseModule(id, string(buf))

	if err != nil {
		switch err := err.(type) {
		case ast.Errors:
			handleErrorAST(w, 400, compileModErrMsg, err)
		default:
			handleError(w, 400, err)
		}
		return
	}

	if parsedMod == nil {
		handleErrorf(w, 400, "refusing to add empty module")
		return
	}

	txn, err := s.store.NewTransaction(ctx)

	if err != nil {
		handleErrorAuto(w, err)
		return
	}

	defer s.store.Close(ctx, txn)

	mods := s.store.ListPolicies(txn)
	mods[id] = parsedMod

	c := ast.NewCompiler()

	if c.Compile(mods); c.Failed() {
		handleErrorAST(w, 400, compileModErrMsg, c.Errors)
		return
	}

	if err := s.store.InsertPolicy(txn, id, parsedMod, buf, s.persist); err != nil {
		handleErrorAuto(w, err)
		return
	}

	s.setCompiler(c)

	policy := &policyV1{
		ID:     id,
		Module: c.Modules[id],
	}

	handleResponseJSON(w, 200, policy, true)
}
Example #18
0
func ExampleEval() {
	// 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 := storage.New(storage.InMemoryWithJSONConfig(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.Close(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 request, tracing configuration,
	// etc. can be set on the Topdown object.
	t := topdown.New(ctx, query, compiler, store, txn)

	result := []interface{}{}

	// Execute the query and provide a callbakc function to accumulate the results.
	err = topdown.Eval(t, func(t *topdown.Topdown) error {

		// Each variable in the query will have an associated "binding" in the context.
		x := t.Binding(ast.Var("x"))

		// The bindings are ast.Value types so we will convert to a native Go value here.
		v, err := topdown.ValueToInterface(x, t)
		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>
}
Example #19
0
func ExampleQueryCompiler_Compile() {

	// Define an input module that will be compiled.
	exampleModule := `

		package opa.example

		import data.foo
		import request.bar

		p[x] :- foo[x], not bar[x], x >= min_x

		min_x = 100

	`

	// Parse the input module to obtain the AST representation.
	mod, err := ast.ParseModule("my_module", exampleModule)
	if err != nil {
		fmt.Println("Parse error:", err)
	}

	// Create a new compiler instance and compile the module.
	c := ast.NewCompiler()

	mods := map[string]*ast.Module{
		"my_module": mod,
	}

	if c.Compile(mods); c.Failed() {
		fmt.Println("Compile error:", c.Errors)
	}

	// Obtain the QueryCompiler from the compiler instance. Note, we will
	// compile this query within the context of the opa.example package and
	// declare that a query input named "queryinput" must be supplied.
	qc := c.QueryCompiler().
		WithContext(
			ast.NewQueryContext(
				// Note, the ast.MustParse<X> functions are meant for test
				// purposes only. They will panic if an error occurs. Prefer the
				// ast.Parse<X> functions that return meaningful error messages
				// instead.
				ast.MustParsePackage("package opa.example"),
				ast.MustParseImports("import request.queryinput"),
			))

	// Parse the input query to obtain the AST representation.
	query, err := ast.ParseBody("p[x], x < queryinput")
	if err != nil {
		fmt.Println("Parse error:", err)
	}

	compiled, err := qc.Compile(query)
	if err != nil {
		fmt.Println("Compile error:", err)
	}

	fmt.Println("Compiled:", compiled)

	// Output:
	//
	// Compiled: data.opa.example.p[x], lt(x, request.queryinput)
}