Skip to content

Commit

Permalink
Merge pull request #1231 from alesstimec/openfga-monitoring
Browse files Browse the repository at this point in the history
Adds monitoring for OpenFGA.
  • Loading branch information
alesstimec authored Jun 12, 2024
2 parents 167eb0c + bdd43b5 commit 19947c2
Show file tree
Hide file tree
Showing 2 changed files with 56 additions and 6 deletions.
49 changes: 43 additions & 6 deletions internal/openfga/openfga.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
"strings"

"github.com/canonical/jimm/internal/errors"
"github.com/canonical/jimm/internal/servermon"
cofga "github.com/canonical/ofga"
"github.com/juju/names/v5"

Expand Down Expand Up @@ -124,17 +125,35 @@ func (o *OFGAClient) listObjects(ctx context.Context, user *Tag, relation Relati
}

// AddRelation adds given relations (tuples).
func (o *OFGAClient) AddRelation(ctx context.Context, tuples ...Tuple) error {
func (o *OFGAClient) AddRelation(ctx context.Context, tuples ...Tuple) (err error) {
op := errors.Op("openfga.AddRelation")

durationObserver := servermon.DurationObserver(servermon.OpenFGACallDurationHistogram, string(op))
defer durationObserver()
defer servermon.ErrorCounter(servermon.OpenFGACallErrorCount, &err, string(op))

return o.cofgaClient.AddRelation(ctx, tuples...)
}

// RemoveRelation removes given relations (tuples).
func (o *OFGAClient) RemoveRelation(ctx context.Context, tuples ...Tuple) error {
func (o *OFGAClient) RemoveRelation(ctx context.Context, tuples ...Tuple) (err error) {
op := errors.Op("openfga.RemoveRelation")

durationObserver := servermon.DurationObserver(servermon.OpenFGACallDurationHistogram, string(op))
defer durationObserver()
defer servermon.ErrorCounter(servermon.OpenFGACallErrorCount, &err, string(op))

return o.cofgaClient.RemoveRelation(ctx, tuples...)
}

// ListObjects returns all object IDs of <objType> that a user has the relation <relation> to.
func (o *OFGAClient) ListObjects(ctx context.Context, user *Tag, relation Relation, objType Kind, contextualTuples []Tuple) ([]Tag, error) {
func (o *OFGAClient) ListObjects(ctx context.Context, user *Tag, relation Relation, objType Kind, contextualTuples []Tuple) (_ []Tag, err error) {
op := errors.Op("openfga.ListObjects")

durationObserver := servermon.DurationObserver(servermon.OpenFGACallDurationHistogram, string(op))
defer durationObserver()
defer servermon.ErrorCounter(servermon.OpenFGACallErrorCount, &err, string(op))

return o.listObjects(ctx, user, relation, objType, contextualTuples)
}

Expand All @@ -143,22 +162,40 @@ func (o *OFGAClient) ListObjects(ctx context.Context, user *Tag, relation Relati
// See: https://openfga.dev/api/service#/Relationship%20Tuples/Read
//
// You may read via pagination utilising the continuation token returned from the request.
func (o *OFGAClient) ReadRelatedObjects(ctx context.Context, tuple Tuple, pageSize int32, continuationToken string) ([]Tuple, string, error) {
func (o *OFGAClient) ReadRelatedObjects(ctx context.Context, tuple Tuple, pageSize int32, continuationToken string) (_ []Tuple, _ string, err error) {
op := errors.Op("openfga.ReadRelatedObjects")

durationObserver := servermon.DurationObserver(servermon.OpenFGACallDurationHistogram, string(op))
defer durationObserver()
defer servermon.ErrorCounter(servermon.OpenFGACallErrorCount, &err, string(op))

return o.getRelatedObjects(ctx, tuple, pageSize, continuationToken)
}

// CheckRelation verifies that a user (or object) is allowed to access the target object by the specified relation.
//
// It will return a bool of simply true or false, denoting authorisation, and an error.
func (o *OFGAClient) CheckRelation(ctx context.Context, tuple Tuple, trace bool) (bool, error) {
func (o *OFGAClient) CheckRelation(ctx context.Context, tuple Tuple, trace bool) (_ bool, err error) {
op := errors.Op("openfga.CheckRelation")

durationObserver := servermon.DurationObserver(servermon.OpenFGACallDurationHistogram, string(op))
defer durationObserver()
defer servermon.ErrorCounter(servermon.OpenFGACallErrorCount, &err, string(op))

if trace {
return o.cofgaClient.CheckRelationWithTracing(ctx, tuple)
}
return o.cofgaClient.CheckRelation(ctx, tuple)
}

// removeTuples iteratively reads through all the tuples with the parameters as supplied by tuple and deletes them.
func (o *OFGAClient) removeTuples(ctx context.Context, tuple Tuple) error {
func (o *OFGAClient) removeTuples(ctx context.Context, tuple Tuple) (err error) {
op := errors.Op("openfga.removeTuples")

durationObserver := servermon.DurationObserver(servermon.OpenFGACallDurationHistogram, string(op))
defer durationObserver()
defer servermon.ErrorCounter(servermon.OpenFGACallErrorCount, &err, string(op))

// Note (babakks): an obvious improvement to this function is to make it work
// atomically and remove all the tuples in a transaction. At the moment, it's
// not simple, because OpenFGA supports limited number of write operation per
Expand Down
13 changes: 13 additions & 0 deletions internal/servermon/monitoring.go
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,19 @@ var (
Name: "error_total",
Help: "The number of database errors.",
}, []string{"method"})
OpenFGACallDurationHistogram = promauto.NewHistogramVec(prometheus.HistogramOpts{
Namespace: "jimm",
Subsystem: "openfga",
Name: "call_duration_seconds",
Help: "Histogram of openfga call time in seconds",
Buckets: []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5, 10},
}, []string{"method"})
OpenFGACallErrorCount = promauto.NewCounterVec(prometheus.CounterOpts{
Namespace: "jimm",
Subsystem: "openfga",
Name: "error_total",
Help: "The number of openfga call errors.",
}, []string{"method"})
ConcurrentWebsocketConnections = promauto.NewGauge(prometheus.GaugeOpts{
Namespace: "jimm",
Subsystem: "websocket",
Expand Down

0 comments on commit 19947c2

Please sign in to comment.