Skip to content

Commit

Permalink
support both config object (for cobra bindings) and functional options
Browse files Browse the repository at this point in the history
for datastore
  • Loading branch information
ecordell committed Dec 7, 2021
1 parent 3dbe72f commit 782a9d4
Show file tree
Hide file tree
Showing 10 changed files with 245 additions and 207 deletions.
35 changes: 9 additions & 26 deletions cmd/spicedb/serve.go
Expand Up @@ -22,27 +22,29 @@ import (

"github.com/authzed/spicedb/internal/auth"
"github.com/authzed/spicedb/internal/dashboard"
"github.com/authzed/spicedb/internal/datastore"
"github.com/authzed/spicedb/internal/datastore/proxy"
combineddispatch "github.com/authzed/spicedb/internal/dispatch/combined"
"github.com/authzed/spicedb/internal/gateway"
"github.com/authzed/spicedb/internal/middleware/servicespecific"
"github.com/authzed/spicedb/internal/namespace"
"github.com/authzed/spicedb/internal/services"
v1alpha1svc "github.com/authzed/spicedb/internal/services/v1alpha1"
"github.com/authzed/spicedb/pkg/cmd/serve"
cmdlib "github.com/authzed/spicedb/pkg/cmd"
logmw "github.com/authzed/spicedb/pkg/middleware/logging"
"github.com/authzed/spicedb/pkg/middleware/requestid"
"github.com/authzed/spicedb/pkg/validationfile"
)

func registerServeCmd(rootCmd *cobra.Command) {
var datastoreOptions cmdlib.DatastoreConfig
serveCmd := &cobra.Command{
Use: "serve",
Short: "serve the permissions database",
Long: "A database that stores, computes, and validates application permissions",
PreRunE: defaultPreRunE,
Run: serveRun,
Run: func(cmd *cobra.Command, args []string) {
serveRun(cmd, args, datastoreOptions)
},
Example: fmt.Sprintf(` %s:
spicedb serve --grpc-preshared-key "somerandomkeyhere"
Expand All @@ -62,8 +64,7 @@ func registerServeCmd(rootCmd *cobra.Command) {
}

// Flags for the datastore
var datastoreOptions serve.Options
serve.RegisterDatastoreFlags(serveCmd, &datastoreOptions)
cmdlib.RegisterDatastoreFlags(serveCmd, &datastoreOptions)
serveCmd.Flags().Bool("datastore-readonly", false, "set the service to read-only mode")
serveCmd.Flags().StringSlice("datastore-bootstrap-files", []string{}, "bootstrap data yaml files to load")
serveCmd.Flags().Bool("datastore-bootstrap-overwrite", false, "overwrite any existing data with bootstrap data")
Expand Down Expand Up @@ -102,31 +103,13 @@ func registerServeCmd(rootCmd *cobra.Command) {
rootCmd.AddCommand(serveCmd)
}

func serveRun(cmd *cobra.Command, args []string) {
func serveRun(cmd *cobra.Command, args []string, datastoreOpts cmdlib.DatastoreConfig) {
token := cobrautil.MustGetStringExpanded(cmd, "grpc-preshared-key")
if len(token) < 1 {
log.Fatal().Msg("a preshared key must be provided via --grpc-preshared-key to authenticate API requests")
}

datastoreEngine := cobrautil.MustGetStringExpanded(cmd, "datastore-engine")
ds, err := serve.NewDatastore(
datastore.Engine(datastoreEngine),
serve.WithRevisionQuantization(cobrautil.MustGetDuration(cmd, "datastore-revision-fuzzing-duration")),
serve.WithGCWindow(cobrautil.MustGetDuration(cmd, "datastore-gc-window")),
serve.WithURI(cobrautil.MustGetStringExpanded(cmd, "datastore-conn-uri")),
serve.WithMaxIdleTime(cobrautil.MustGetDuration(cmd, "datastore-conn-max-idletime")),
serve.WithMaxLifetime(cobrautil.MustGetDuration(cmd, "datastore-conn-max-lifetime")),
serve.WithMaxOpenConns(cobrautil.MustGetInt(cmd, "datastore-conn-max-open")),
serve.WithMinOpenConns(cobrautil.MustGetInt(cmd, "datastore-conn-min-open")),
serve.WithSplitQuerySize(cobrautil.MustGetStringExpanded(cmd, "datastore-query-split-size")),
serve.WithFollowerReadDelay(cobrautil.MustGetDuration(cmd, "datastore-follower-read-delay-duration")),
serve.WithMaxRetries(cobrautil.MustGetInt(cmd, "datastore-max-tx-retries")),
serve.WithOverlapKey(cobrautil.MustGetStringExpanded(cmd, "datastore-tx-overlap-key")),
serve.WithOverlapStrategy(cobrautil.MustGetStringExpanded(cmd, "datastore-tx-overlap-strategy")),
serve.WithHealthCheckPeriod(cobrautil.MustGetDuration(cmd, "datastore-conn-healthcheck-interval")),
serve.WithGCInterval(cobrautil.MustGetDuration(cmd, "datastore-gc-interval")),
serve.WithGCMaxOperationTime(cobrautil.MustGetDuration(cmd, "datastore-gc-max-operation-time")),
)
ds, err := cmdlib.NewDatastore(datastoreOpts.ToOption())
if err != nil {
log.Fatal().Err(err).Msg("failed to init datastore")
}
Expand Down Expand Up @@ -288,7 +271,7 @@ func serveRun(cmd *cobra.Command, args []string) {
dashboardSrv.Handler = dashboard.NewHandler(
cobrautil.MustGetStringExpanded(cmd, "grpc-addr"),
cobrautil.MustGetStringExpanded(cmd, "grpc-tls-cert-path") != "" && cobrautil.MustGetStringExpanded(cmd, "grpc-tls-key-path") != "",
datastoreEngine,
datastoreOpts.Engine,
ds,
)
go func() {
Expand Down
1 change: 1 addition & 0 deletions go.mod
Expand Up @@ -14,6 +14,7 @@ require (
github.com/containerd/continuity v0.2.1 // indirect
github.com/dgraph-io/ristretto v0.1.0
github.com/docker/docker v20.10.9+incompatible // indirect
github.com/ecordell/optgen v0.0.4
github.com/emirpasic/gods v1.12.0
github.com/envoyproxy/protoc-gen-validate v0.6.2
github.com/fatih/color v1.13.0
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Expand Up @@ -136,6 +136,8 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do
github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw=
github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/cyphar/filepath-securejoin v0.2.2/go.mod h1:FpkQEhXnPnOthhzymB7CGsFk2G9VLXONKD9G7QGMM+4=
github.com/dave/jennifer v1.4.0 h1:tNJFJmLDVTLu+v05mVZ88RINa3vQqnyyWkTKWYz0CwE=
github.com/dave/jennifer v1.4.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
Expand All @@ -154,6 +156,8 @@ github.com/docker/go-units v0.4.0 h1:3uh0PgVws3nIA0Q+MwDC8yjEPf9zjRfZZWXZYDct3Tw
github.com/docker/go-units v0.4.0/go.mod h1:fgPhTUdO+D/Jk86RDLlptpiXQzgHJF7gydDDbaIK4Dk=
github.com/dustin/go-humanize v1.0.0 h1:VSnTsYCnlFHaM2/igO1h6X3HA71jcobQuxemgkq4zYo=
github.com/dustin/go-humanize v1.0.0/go.mod h1:HtrtbFcZ19U5GC7JDqmcUSB87Iq5E25KnS6fMYU6eOk=
github.com/ecordell/optgen v0.0.4 h1:0ytRxj6f/LBl7laGDxiUjjR+ioAqr4WMLpS84D8AD10=
github.com/ecordell/optgen v0.0.4/go.mod h1:bAPkLVWcBlTX5EkXW0UTPRj3+yjq2I6VLgH8OasuQEM=
github.com/emirpasic/gods v1.12.0 h1:QAUIPSaCu4G+POclxeqb3F+WPpdKqFGlw36+yOzGlrg=
github.com/emirpasic/gods v1.12.0/go.mod h1:YfzfFFoVP/catgzJb4IKIqXjX78Ha8FMSDh3ymbK86o=
github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4=
Expand Down Expand Up @@ -767,6 +771,7 @@ golang.org/x/mod v0.3.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.0/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.1/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
golang.org/x/mod v0.5.0 h1:UG21uOlmZabA4fW5i7ZX6bjw1xELEGg/ZLgZq9auk/Q=
golang.org/x/mod v0.5.0/go.mod h1:5OXOZSfqPIIbmVBIIKWRFfZjPR0E5r58TLhUjH0a2Ro=
golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
Expand Down Expand Up @@ -999,6 +1004,7 @@ golang.org/x/tools v0.0.0-20200515010526-7d3b6ebf133d/go.mod h1:EkVYQZoAsY45+roY
golang.org/x/tools v0.0.0-20200522201501-cb1345f3a375/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200618134242-20370b0cb4b2/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200619180055-7c47624df98f/go.mod h1:EkVYQZoAsY45+roYkvgYkIh4xh/qjgUK9TdY2XT94GE=
golang.org/x/tools v0.0.0-20200717024301-6ddee64345a6/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200729194436-6467de6f59a7/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200804011535-6c149bb5ef0d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
golang.org/x/tools v0.0.0-20200825202427-b303f430e36d/go.mod h1:njjCfa9FT2d7l9Bc6FUM5FLjQPp3cFF28FI3qnDFljA=
Expand Down
28 changes: 0 additions & 28 deletions internal/datastore/crdb/crdb.go
Expand Up @@ -18,7 +18,6 @@ import (

"github.com/authzed/spicedb/internal/datastore"
"github.com/authzed/spicedb/internal/datastore/crdb/migrations"
"github.com/authzed/spicedb/pkg/cmd/serve"
)

var (
Expand Down Expand Up @@ -50,35 +49,8 @@ const (
querySelectNow = "SELECT cluster_logical_timestamp()"
queryReturningTimestamp = "RETURNING cluster_logical_timestamp()"
queryShowZoneConfig = "SHOW ZONE CONFIGURATION FOR RANGE default;"

cockroachEngine datastore.Engine = "cockroach"
)

func init() {
serve.RegisterEngine(cockroachEngine, newFromDatastoreOptions)
}

func newFromDatastoreOptions(opts serve.Options) (datastore.Datastore, error) {
splitQuerySize, err := units.ParseBase2Bytes(opts.SplitQuerySize)
if err != nil {
return nil, fmt.Errorf("failed to parse split query size: %w", err)
}
return NewCRDBDatastore(
opts.URI,
GCWindow(opts.GCWindow),
RevisionQuantization(opts.RevisionQuantization),
ConnMaxIdleTime(opts.MaxIdleTime),
ConnMaxLifetime(opts.MaxLifetime),
MaxOpenConns(opts.MaxOpenConns),
MinOpenConns(opts.MinOpenConns),
SplitAtEstimatedQuerySize(splitQuerySize),
FollowerReadDelay(opts.FollowerReadDelay),
MaxRetries(opts.MaxRetries),
OverlapKey(opts.OverlapKey),
OverlapStrategy(opts.OverlapStrategy),
)
}

// NewCRDBDatastore initializes a SpiceDB datastore that uses a CockroachDB
// database while leveraging its AOST functionality.
func NewCRDBDatastore(url string, options ...Option) (datastore.Datastore, error) {
Expand Down
5 changes: 1 addition & 4 deletions internal/datastore/datastore.go
Expand Up @@ -80,7 +80,7 @@ type GraphDatastore interface {
// from a subject relation onward from the datastore.
ReverseQueryTuplesFromSubjectRelation(subjectNamespace, subjectRelation string, revision Revision) ReverseTupleQuery

//  ReverseQueryTuplesFromSubjectNamespace creates a builder for reading
// ReverseQueryTuplesFromSubjectNamespace creates a builder for reading
// tuples from a subject namespace onward from the datastore.
ReverseQueryTuplesFromSubjectNamespace(subjectNamespace string, revision Revision) ReverseTupleQuery

Expand Down Expand Up @@ -150,6 +150,3 @@ type Revision = decimal.Decimal
// revision type in the future a bit easier if necessary. Implementations
// should use any time they want to signal an empty/error revision.
var NoRevision Revision

// Engine represents the type of a datastore engine, i.e. Cockroach or Postgres
type Engine string
13 changes: 0 additions & 13 deletions internal/datastore/memdb/memdb.go
Expand Up @@ -11,24 +11,11 @@ import (
v1 "github.com/authzed/authzed-go/proto/authzed/api/v1"
"github.com/hashicorp/go-memdb"
"github.com/jzelinskie/stringz"
"github.com/rs/zerolog/log"
"github.com/shopspring/decimal"

"github.com/authzed/spicedb/internal/datastore"
"github.com/authzed/spicedb/pkg/cmd/serve"
)

const memoryEngine datastore.Engine = "memory"

func init() {
serve.RegisterEngine(memoryEngine, newFromDatastoreOptions)
}

func newFromDatastoreOptions(opts serve.Options) (datastore.Datastore, error) {
log.Warn().Msg("in-memory datastore is not persistent and not feasible to run in a high availability fashion")
return NewMemdbDatastore(0, opts.RevisionQuantization, opts.GCWindow, 0)
}

// DisableGC is a convenient constant for setting the garbage collection
// interval high enough that it will never run.
const DisableGC = time.Duration(math.MaxInt64)
Expand Down
26 changes: 0 additions & 26 deletions internal/datastore/postgres/postgres.go
Expand Up @@ -24,7 +24,6 @@ import (

"github.com/authzed/spicedb/internal/datastore"
"github.com/authzed/spicedb/internal/datastore/postgres/migrations"
"github.com/authzed/spicedb/pkg/cmd/serve"
)

const (
Expand Down Expand Up @@ -56,8 +55,6 @@ const (
tracingDriverName = "postgres-tracing"

batchDeleteSize = 1000

postgresEngine datastore.Engine = "postgres"
)

var (
Expand Down Expand Up @@ -86,29 +83,6 @@ var (

func init() {
dbsql.Register(tracingDriverName, sqlmw.Driver(stdlib.GetDefaultDriver(), new(traceInterceptor)))
serve.RegisterEngine(postgresEngine, newFromDatastoreOptions)
}

func newFromDatastoreOptions(opts serve.Options) (datastore.Datastore, error) {
splitQuerySize, err := units.ParseBase2Bytes(opts.SplitQuerySize)
if err != nil {
return nil, fmt.Errorf("failed to parse split query size: %w", err)
}
return NewPostgresDatastore(
opts.URI,
GCWindow(opts.GCWindow),
RevisionFuzzingTimedelta(opts.RevisionQuantization),
ConnMaxIdleTime(opts.MaxIdleTime),
ConnMaxLifetime(opts.MaxLifetime),
MaxOpenConns(opts.MaxOpenConns),
MinOpenConns(opts.MinOpenConns),
SplitAtEstimatedQuerySize(splitQuerySize),
HealthCheckPeriod(opts.HealthCheckPeriod),
GCInterval(opts.GCInterval),
GCMaxOperationTime(opts.GCMaxOperationTime),
EnablePrometheusStats(),
EnableTracing(),
)
}

var (
Expand Down

0 comments on commit 782a9d4

Please sign in to comment.