Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add EvaluationMeta empty interface to each Result #263

Merged
merged 7 commits into from
Dec 7, 2022
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions constraint/pkg/client/drivers/local/driver.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"sort"
"strings"
"sync"
"time"

"github.com/open-policy-agent/frameworks/constraint/pkg/apis/constraints"
"github.com/open-policy-agent/frameworks/constraint/pkg/client/drivers"
Expand Down Expand Up @@ -72,6 +73,20 @@ type Driver struct {
clientCertWatcher *certwatcher.CertWatcher
}

// regoResultMeta has rego specific metadata for a result.
type regoResultMeta struct {
// templateRunTime is the number of milliseconds it took to evaluate all constraints for a template.
templateRunTime float64
// engineType is an engine set string for the kind of underlying engine that was used for a client.Review() call.
acpana marked this conversation as resolved.
Show resolved Hide resolved
engineType string
// constraintCount indicates how many constraints were evaluated for an underlying engine eval call.
constraintCount uint
}

func (rm *regoResultMeta) EngineStatsString() string {
return fmt.Sprintf("totalTemplateRuntime: %.4f, engineType: %s, constraintCount: %d", rm.templateRunTime, rm.engineType, rm.constraintCount)
acpana marked this conversation as resolved.
Show resolved Hide resolved
acpana marked this conversation as resolved.
Show resolved Hide resolved
}

// AddTemplate adds templ to Driver. Normalizes modules into usable forms for
// use in queries.
func (d *Driver) AddTemplate(ctx context.Context, templ *templates.ConstraintTemplate) error {
Expand Down Expand Up @@ -238,6 +253,7 @@ func (d *Driver) Query(ctx context.Context, target string, constraints []*unstru
defer d.mtx.RUnlock()

for kind, kindConstraints := range constraintsByKind {
evalStartTime := time.Now()
compiler := d.compilers.getCompiler(target, kind)
if compiler == nil {
// The Template was just removed, so the Driver is in an inconsistent
Expand All @@ -254,6 +270,7 @@ func (d *Driver) Query(ctx context.Context, target string, constraints []*unstru
}

resultSet, trace, err := d.eval(ctx, compiler, target, path, parsedInput, opts...)
evalEndTime := time.Since(evalStartTime)
if err != nil {
resultSet = make(rego.ResultSet, 0, len(kindConstraints))
for _, constraint := range kindConstraints {
Expand All @@ -279,6 +296,14 @@ func (d *Driver) Query(ctx context.Context, target string, constraints []*unstru
return nil, nil, err
}

for _, result := range kindResults {
result.ResultMeta = &regoResultMeta{
templateRunTime: float64(evalEndTime.Nanoseconds()) / 1000000,
engineType: "rego",
constraintCount: uint(len(kindResults)),
}
}

results = append(results, kindResults...)
}

Expand Down
12 changes: 12 additions & 0 deletions constraint/pkg/client/drivers/local/driver_unit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"net/http"
"os"
"sort"
"strings"
"testing"

"github.com/google/go-cmp/cmp"
Expand Down Expand Up @@ -171,6 +172,17 @@ func TestDriver_Query(t *testing.T) {
if len(res) == 0 {
t.Fatalf("got 0 errors on data-less query; want 1")
}

statsString := res[0].ResultMeta.EngineStatsString()
partOfExcpectedStatsString := fmt.Sprintf("engineType: rego, constraintCount: 1")
if !strings.Contains(statsString, partOfExcpectedStatsString) {
t.Fatalf("did not find expected string: %s, in: %s", partOfExcpectedStatsString, statsString)
}

partOfNonExpectingString := "totalTemplateRuntime: 0.0000"
if strings.Contains(statsString, partOfNonExpectingString) {
t.Fatalf("did not expect string: %s, in: %s", partOfNonExpectingString, statsString)
}
}

func TestDriver_ExternalData(t *testing.T) {
Expand Down
42 changes: 42 additions & 0 deletions constraint/pkg/client/e2e_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package client_test
import (
"context"
"errors"
"strconv"
"testing"

"github.com/google/go-cmp/cmp"
Expand Down Expand Up @@ -727,3 +728,44 @@ func TestE2E_Tracing(t *testing.T) {
})
}
}

// TestE2E_Review_ResultMeta tests that we can get stats out of evaluated constraints.
func TestE2E_Review_ResultMeta(t *testing.T) {
ctx := context.Background()
c := clienttest.New(t)
ct := clienttest.TemplateCheckData()
_, err := c.AddTemplate(ctx, ct)
if err != nil {
t.Fatal(err)
}
numConstrains := 3

for i := 1; i < numConstrains+1; i++ {
name := "constraint-" + strconv.Itoa(i)
constraint := cts.MakeConstraint(t, clienttest.KindCheckData, name, cts.WantData("bar"))
_, err = c.AddConstraint(ctx, constraint)
if err != nil {
t.Fatal(err)
}
}

review := handlertest.Review{
Object: handlertest.Object{
Name: "foo",
Data: "qux",
},
}

responses, err := c.Review(ctx, review)
if err != nil {
t.Fatal(err)
}

results := responses.Results()

for _, result := range results {
if result.ResultMeta.EngineStatsString() == "" {
t.Fatalf("expected to have a stats string, got empty string")
}
}
}
12 changes: 12 additions & 0 deletions constraint/pkg/types/validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@ type Result struct {

// The enforcement action of the constraint
EnforcementAction string `json:"enforcementAction,omitempty"`

ResultMeta ResultMeta
}

// Response is a collection of Constraint violations for a particular Target.
Expand Down Expand Up @@ -134,3 +136,13 @@ func (r *Responses) TraceDump() string {
}
return b.String()
}

// ResultMeta defines an interface to expose metadata for a Result.
type ResultMeta interface {
// EngineStatsString gives an amorphous representation of engine stats
// such as latency, engine type or the number of constraints evalauted
// against a template. The underlying enigne type defines and implements
// structs for this interface. This function is primarily inteded for logging
// out for the consumers of this library.
EngineStatsString() string
acpana marked this conversation as resolved.
Show resolved Hide resolved
}