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 }
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 }
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> }
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} }
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 }
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[""] }
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 }
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 }
// 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 }
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) }
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) }
// 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 }
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 }
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) } }
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 }
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) }
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) }
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> }
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) }