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

Remove LookupResources v1 implementation #2099

Merged
merged 7 commits into from
Oct 28, 2024
Merged
Show file tree
Hide file tree
Changes from all 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
18 changes: 5 additions & 13 deletions internal/services/integrationtesting/consistency_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,15 +60,10 @@ func TestConsistency(t *testing.T) {
dispatcherKind := dispatcherKind

t.Run(dispatcherKind, func(t *testing.T) {
for _, useLRV2 := range []bool{false, true} {
useLRV2 := useLRV2
t.Run(fmt.Sprintf("lrv2-%t", useLRV2), func(t *testing.T) {
for _, chunkSize := range []uint16{5, 10} {
t.Run(fmt.Sprintf("lrv2-%t", useLRV2), func(t *testing.T) {
t.Parallel()
runConsistencyTestSuiteForFile(t, filePath, dispatcherKind == "caching", chunkSize, useLRV2)
})
}
for _, chunkSize := range []uint16{5, 10} {
t.Run(fmt.Sprintf("chunk-size-%d", chunkSize), func(t *testing.T) {
t.Parallel()
runConsistencyTestSuiteForFile(t, filePath, dispatcherKind == "caching", chunkSize)
})
}
})
Expand All @@ -77,11 +72,8 @@ func TestConsistency(t *testing.T) {
}
}

func runConsistencyTestSuiteForFile(t *testing.T, filePath string, useCachingDispatcher bool, chunkSize uint16, useLRV2 bool) {
func runConsistencyTestSuiteForFile(t *testing.T, filePath string, useCachingDispatcher bool, chunkSize uint16) {
options := []server.ConfigOption{server.WithDispatchChunkSize(chunkSize)}
if useLRV2 {
options = append(options, server.WithEnableExperimentalLookupResources(true))
}

cad := consistencytestutil.LoadDataAndCreateClusterForTesting(t, filePath, testTimedelta, options...)

Expand Down
146 changes: 3 additions & 143 deletions internal/services/v1/permissions.go
Original file line number Diff line number Diff line change
Expand Up @@ -396,155 +396,15 @@ func TranslateExpansionTree(node *core.RelationTupleTreeNode) *v1.PermissionRela
const lrv2CursorFlag = "lrv2"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

keep the cursor flag; we might need it again in the future and we don't want to break existing cursors. we should just return an error if the cursor does not have it

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see this change reverted


func (ps *permissionServer) LookupResources(req *v1.LookupResourcesRequest, resp v1.PermissionsService_LookupResourcesServer) error {
// If the cursor specifies that this is a LookupResources2 request, then that implementation must
// be used.
// NOTE: LRv2 is the only valid option, and we'll expect that all cursors include that flag.
// This is to preserve backward-compatibility in the meantime.
if req.OptionalCursor != nil {
_, ok, err := cursor.GetCursorFlag(req.OptionalCursor, lrv2CursorFlag)
_, _, err := cursor.GetCursorFlag(req.OptionalCursor, lrv2CursorFlag)
if err != nil {
return ps.rewriteError(resp.Context(), err)
}

if ok {
return ps.lookupResources2(req, resp)
}
}

if ps.config.UseExperimentalLookupResources2 {
return ps.lookupResources2(req, resp)
}

return ps.lookupResources1(req, resp)
}

func (ps *permissionServer) lookupResources1(req *v1.LookupResourcesRequest, resp v1.PermissionsService_LookupResourcesServer) error {
if req.OptionalLimit > 0 && req.OptionalLimit > ps.config.MaxLookupResourcesLimit {
return ps.rewriteError(resp.Context(), NewExceedsMaximumLimitErr(uint64(req.OptionalLimit), uint64(ps.config.MaxLookupResourcesLimit)))
}

ctx := resp.Context()

atRevision, revisionReadAt, err := consistency.RevisionFromContext(ctx)
if err != nil {
return ps.rewriteError(ctx, err)
}

ds := datastoremw.MustFromContext(ctx).SnapshotReader(atRevision)

if err := namespace.CheckNamespaceAndRelations(ctx,
[]namespace.TypeAndRelationToCheck{
{
NamespaceName: req.ResourceObjectType,
RelationName: req.Permission,
AllowEllipsis: false,
},
{
NamespaceName: req.Subject.Object.ObjectType,
RelationName: normalizeSubjectRelation(req.Subject),
AllowEllipsis: true,
},
}, ds); err != nil {
return ps.rewriteError(ctx, err)
}

respMetadata := &dispatch.ResponseMeta{
DispatchCount: 1,
CachedDispatchCount: 0,
DepthRequired: 1,
DebugInfo: nil,
}
usagemetrics.SetInContext(ctx, respMetadata)

var currentCursor *dispatch.Cursor

lrRequestHash, err := computeLRRequestHash(req)
if err != nil {
return ps.rewriteError(ctx, err)
}

if req.OptionalCursor != nil {
decodedCursor, _, err := cursor.DecodeToDispatchCursor(req.OptionalCursor, lrRequestHash)
if err != nil {
return ps.rewriteError(ctx, err)
}
currentCursor = decodedCursor
}

alreadyPublishedPermissionedResourceIds := map[string]struct{}{}

stream := dispatchpkg.NewHandlingDispatchStream(ctx, func(result *dispatch.DispatchLookupResourcesResponse) error {
found := result.ResolvedResource

dispatchpkg.AddResponseMetadata(respMetadata, result.Metadata)
currentCursor = result.AfterResponseCursor

var partial *v1.PartialCaveatInfo
permissionship := v1.LookupPermissionship_LOOKUP_PERMISSIONSHIP_HAS_PERMISSION
if found.Permissionship == dispatch.ResolvedResource_CONDITIONALLY_HAS_PERMISSION {
permissionship = v1.LookupPermissionship_LOOKUP_PERMISSIONSHIP_CONDITIONAL_PERMISSION
partial = &v1.PartialCaveatInfo{
MissingRequiredContext: found.MissingRequiredContext,
}
} else if req.OptionalLimit == 0 {
if _, ok := alreadyPublishedPermissionedResourceIds[found.ResourceId]; ok {
// Skip publishing the duplicate.
return nil
}

alreadyPublishedPermissionedResourceIds[found.ResourceId] = struct{}{}
}

encodedCursor, err := cursor.EncodeFromDispatchCursor(result.AfterResponseCursor, lrRequestHash, atRevision, nil)
if err != nil {
return ps.rewriteError(ctx, err)
}

err = resp.Send(&v1.LookupResourcesResponse{
LookedUpAt: revisionReadAt,
ResourceObjectId: found.ResourceId,
Permissionship: permissionship,
PartialCaveatInfo: partial,
AfterResultCursor: encodedCursor,
})
if err != nil {
return err
}
return nil
})

bf, err := dispatch.NewTraversalBloomFilter(uint(ps.config.MaximumAPIDepth))
if err != nil {
return err
}

err = ps.dispatch.DispatchLookupResources(
&dispatch.DispatchLookupResourcesRequest{
Metadata: &dispatch.ResolverMeta{
AtRevision: atRevision.String(),
DepthRemaining: ps.config.MaximumAPIDepth,
TraversalBloom: bf,
},
ObjectRelation: &core.RelationReference{
Namespace: req.ResourceObjectType,
Relation: req.Permission,
},
Subject: &core.ObjectAndRelation{
Namespace: req.Subject.Object.ObjectType,
ObjectId: req.Subject.Object.ObjectId,
Relation: normalizeSubjectRelation(req.Subject),
},
Context: req.Context,
OptionalCursor: currentCursor,
OptionalLimit: req.OptionalLimit,
},
stream)
if err != nil {
return ps.rewriteError(ctx, err)
}

return nil
}

func (ps *permissionServer) lookupResources2(req *v1.LookupResourcesRequest, resp v1.PermissionsService_LookupResourcesServer) error {
if req.OptionalLimit > 0 && req.OptionalLimit > ps.config.MaxLookupResourcesLimit {
return ps.rewriteError(resp.Context(), NewExceedsMaximumLimitErr(uint64(req.OptionalLimit), uint64(ps.config.MaxLookupResourcesLimit)))
}
Expand Down
9 changes: 4 additions & 5 deletions internal/services/v1/permissions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -637,11 +637,10 @@ func TestLookupResources(t *testing.T) {
memdb.DisableGC,
true,
testserver.ServerConfig{
MaxUpdatesPerWrite: 1000,
MaxPreconditionsCount: 1000,
StreamingAPITimeout: 30 * time.Second,
MaxRelationshipContextSize: 25000,
UseExperimentalLookupResources2: useV2,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a bunch of changes like this that are just propagating the option removal.

MaxUpdatesPerWrite: 1000,
MaxPreconditionsCount: 1000,
StreamingAPITimeout: 30 * time.Second,
MaxRelationshipContextSize: 25000,
},
tf.StandardDatastoreWithData,
)
Expand Down
4 changes: 0 additions & 4 deletions internal/services/v1/relationships.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,6 @@ type PermissionsServerConfig struct {
// MaxBulkExportRelationshipsLimit defines the maximum number of relationships that can be
// exported in a single BulkExportRelationships call.
MaxBulkExportRelationshipsLimit uint32

// UseExperimentalLookupResources2 enables the experimental LookupResources2 API.
UseExperimentalLookupResources2 bool
}

// NewPermissionsServer creates a PermissionsServiceServer instance.
Expand All @@ -117,7 +114,6 @@ func NewPermissionsServer(
MaxDeleteRelationshipsLimit: defaultIfZero(config.MaxDeleteRelationshipsLimit, 1_000),
MaxLookupResourcesLimit: defaultIfZero(config.MaxLookupResourcesLimit, 1_000),
MaxBulkExportRelationshipsLimit: defaultIfZero(config.MaxBulkExportRelationshipsLimit, 100_000),
UseExperimentalLookupResources2: config.UseExperimentalLookupResources2,
DispatchChunkSize: defaultIfZero(config.DispatchChunkSize, 100),
}

Expand Down
19 changes: 8 additions & 11 deletions internal/testserver/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,19 +21,17 @@ import (

// ServerConfig is configuration for the test server.
type ServerConfig struct {
MaxUpdatesPerWrite uint16
MaxPreconditionsCount uint16
MaxRelationshipContextSize int
StreamingAPITimeout time.Duration
UseExperimentalLookupResources2 bool
MaxUpdatesPerWrite uint16
MaxPreconditionsCount uint16
MaxRelationshipContextSize int
StreamingAPITimeout time.Duration
}

var DefaultTestServerConfig = ServerConfig{
MaxUpdatesPerWrite: 1000,
MaxPreconditionsCount: 1000,
StreamingAPITimeout: 30 * time.Second,
MaxRelationshipContextSize: 25000,
UseExperimentalLookupResources2: true,
MaxUpdatesPerWrite: 1000,
MaxPreconditionsCount: 1000,
StreamingAPITimeout: 30 * time.Second,
MaxRelationshipContextSize: 25000,
}

// NewTestServer creates a new test server, using defaults for the config.
Expand Down Expand Up @@ -92,7 +90,6 @@ func NewTestServerWithConfigAndDatastore(require *require.Assertions,
server.WithHTTPGateway(util.HTTPServerConfig{HTTPEnabled: false}),
server.WithMetricsAPI(util.HTTPServerConfig{HTTPEnabled: false}),
server.WithDispatchServer(util.GRPCServerConfig{Enabled: false}),
server.WithEnableExperimentalLookupResources(config.UseExperimentalLookupResources2),
server.SetUnaryMiddlewareModification([]server.MiddlewareModification[grpc.UnaryServerInterceptor]{
{
Operation: server.OperationReplaceAllUnsafe,
Expand Down
10 changes: 10 additions & 0 deletions pkg/cmd/serve.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/fatih/color"
"github.com/jzelinskie/cobrautil/v2"
"github.com/jzelinskie/cobrautil/v2/cobraotel"
"github.com/rs/zerolog/log"
"github.com/spf13/cobra"

"github.com/authzed/spicedb/internal/telemetry"
Expand Down Expand Up @@ -159,6 +160,15 @@ func RegisterServeFlags(cmd *cobra.Command, config *server.Config) error {
experimentalFlags := nfs.FlagSet(BoldBlue("Experimental"))
// Flags for experimental features
experimentalFlags.BoolVar(&config.EnableExperimentalLookupResources, "enable-experimental-lookup-resources", true, "enables the experimental version of the lookup resources API")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't remove, as it will break callers. Instead, deprecate it and if someone gives a value of false, issue a warning that the flag will be removed in the future

if err := experimentalFlags.MarkDeprecated("enable-experimental-lookup-resources", "The old implementation of LookupResources has been removed and this flag is a no-op. This flag will be removed in the future."); err != nil {
return fmt.Errorf("failed to mark flag as deprecated: %w", err)
}
if !config.EnableExperimentalLookupResources {
log.Warn().
Bool("value", false).
Msg("The old implementation of LookupResources is no longer available, and a `false` value is no longer valid. Please remove this flag.")
}

experimentalFlags.BoolVar(&config.EnableExperimentalWatchableSchemaCache, "enable-experimental-watchable-schema-cache", false, "enables the experimental schema cache which makes use of the Watch API for automatic updates")
// TODO: these two could reasonably be put in either the Dispatch group or the Experimental group. Is there a preference?
experimentalFlags.StringToStringVar(&config.DispatchSecondaryUpstreamAddrs, "experimental-dispatch-secondary-upstream-addrs", nil, "secondary upstream addresses for dispatches, each with a name")
Expand Down
1 change: 0 additions & 1 deletion pkg/cmd/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -429,7 +429,6 @@ func (c *Config) Complete(ctx context.Context) (RunnableServer, error) {
MaxDeleteRelationshipsLimit: c.MaxDeleteRelationshipsLimit,
MaxLookupResourcesLimit: c.MaxLookupResourcesLimit,
MaxBulkExportRelationshipsLimit: c.MaxBulkExportRelationshipsLimit,
UseExperimentalLookupResources2: c.EnableExperimentalLookupResources,
DispatchChunkSize: c.DispatchChunkSize,
}

Expand Down
1 change: 0 additions & 1 deletion pkg/cmd/testing.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,6 @@ func RegisterTestingFlags(cmd *cobra.Command, config *testserver.Config) {
cmd.Flags().Uint32Var(&config.MaxDeleteRelationshipsLimit, "max-delete-relationships-limit", 1000, "maximum number of relationships that can be deleted in a single request")
cmd.Flags().Uint32Var(&config.MaxLookupResourcesLimit, "max-lookup-resources-limit", 1000, "maximum number of resources that can be looked up in a single request")
cmd.Flags().Uint32Var(&config.MaxBulkExportRelationshipsLimit, "max-bulk-export-relationships-limit", 10_000, "maximum number of relationships that can be exported in a single request")
cmd.Flags().BoolVar(&config.EnableExperimentalLookupResources, "enable-experimental-lookup-resources", false, "enables the experimental version of the lookup resources API")
util.RegisterCommonFlags(cmd)
}

Expand Down
27 changes: 13 additions & 14 deletions pkg/cmd/testserver/testserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,20 +31,19 @@ const (

//go:generate go run github.com/ecordell/optgen -output zz_generated.options.go . Config
type Config struct {
GRPCServer util.GRPCServerConfig `debugmap:"visible"`
ReadOnlyGRPCServer util.GRPCServerConfig `debugmap:"visible"`
HTTPGateway util.HTTPServerConfig `debugmap:"visible"`
ReadOnlyHTTPGateway util.HTTPServerConfig `debugmap:"visible"`
LoadConfigs []string `debugmap:"visible"`
MaximumUpdatesPerWrite uint16 `debugmap:"visible"`
MaximumPreconditionCount uint16 `debugmap:"visible"`
MaxCaveatContextSize int `debugmap:"visible"`
MaxRelationshipContextSize int `debugmap:"visible"`
MaxReadRelationshipsLimit uint32 `debugmap:"visible"`
MaxDeleteRelationshipsLimit uint32 `debugmap:"visible"`
MaxLookupResourcesLimit uint32 `debugmap:"visible"`
MaxBulkExportRelationshipsLimit uint32 `debugmap:"visible"`
EnableExperimentalLookupResources bool `debugmap:"visible"`
GRPCServer util.GRPCServerConfig `debugmap:"visible"`
ReadOnlyGRPCServer util.GRPCServerConfig `debugmap:"visible"`
HTTPGateway util.HTTPServerConfig `debugmap:"visible"`
ReadOnlyHTTPGateway util.HTTPServerConfig `debugmap:"visible"`
LoadConfigs []string `debugmap:"visible"`
MaximumUpdatesPerWrite uint16 `debugmap:"visible"`
MaximumPreconditionCount uint16 `debugmap:"visible"`
MaxCaveatContextSize int `debugmap:"visible"`
MaxRelationshipContextSize int `debugmap:"visible"`
MaxReadRelationshipsLimit uint32 `debugmap:"visible"`
MaxDeleteRelationshipsLimit uint32 `debugmap:"visible"`
MaxLookupResourcesLimit uint32 `debugmap:"visible"`
MaxBulkExportRelationshipsLimit uint32 `debugmap:"visible"`
}

type RunnableTestServer interface {
Expand Down
9 changes: 0 additions & 9 deletions pkg/cmd/testserver/zz_generated.options.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading