diff --git a/changelog/unreleased/spaces-stat.md b/changelog/unreleased/spaces-stat.md new file mode 100644 index 0000000000..102e86967c --- /dev/null +++ b/changelog/unreleased/spaces-stat.md @@ -0,0 +1,6 @@ +Bugfix: Fix spaces stat + +When stating a space e.g. the Share Jail and that space contains another space, in this case a share +then the stat would sometimes get the sub space instead of the Share Jail itself. + +https://github.com/cs3org/reva/pull/2501 diff --git a/internal/grpc/services/gateway/storageprovider.go b/internal/grpc/services/gateway/storageprovider.go index 16d800fd8e..58c191be8b 100644 --- a/internal/grpc/services/gateway/storageprovider.go +++ b/internal/grpc/services/gateway/storageprovider.go @@ -802,7 +802,7 @@ func (s *svc) Unlock(ctx context.Context, req *provider.UnlockRequest) (*provide // Stat returns the Resoure info for a given resource by forwarding the request to the responsible provider. // TODO cache info func (s *svc) Stat(ctx context.Context, req *provider.StatRequest) (*provider.StatResponse, error) { - c, _, ref, err := s.findAndUnwrap(ctx, req.Ref) + c, _, ref, err := s.findAndUnwrapUnique(ctx, req.Ref) if err != nil { return &provider.StatResponse{ Status: status.NewNotFound(ctx, fmt.Sprintf("gateway could not find space for ref=%+v", req.Ref)), @@ -991,6 +991,16 @@ func (s *svc) find(ctx context.Context, ref *provider.Reference) (provider.Provi return client, p[0], err } +func (s *svc) findUnique(ctx context.Context, ref *provider.Reference) (provider.ProviderAPIClient, *registry.ProviderInfo, error) { + p, err := s.findSingleSpace(ctx, ref) + if err != nil { + return nil, nil, err + } + + client, err := s.getStorageProviderClient(ctx, p[0]) + return client, p[0], err +} + // FIXME findAndUnwrap currently just returns the first provider ... which may not be what is needed. // for the ListRecycle call we need an exact match, for Stat and List we need to query all related providers func (s *svc) findAndUnwrap(ctx context.Context, ref *provider.Reference) (provider.ProviderAPIClient, *registry.ProviderInfo, *provider.Reference, error) { @@ -1014,6 +1024,27 @@ func (s *svc) findAndUnwrap(ctx context.Context, ref *provider.Reference) (provi return c, p, relativeReference, nil } +func (s *svc) findAndUnwrapUnique(ctx context.Context, ref *provider.Reference) (provider.ProviderAPIClient, *registry.ProviderInfo, *provider.Reference, error) { + c, p, err := s.findUnique(ctx, ref) + if err != nil { + return nil, nil, nil, err + } + + var ( + root *provider.ResourceId + mountPath string + ) + for _, space := range decodeSpaces(p) { + mountPath = decodePath(space) + root = space.Root + break // TODO can there be more than one space for a path? + } + + relativeReference := unwrap(ref, mountPath, root) + + return c, p, relativeReference, nil +} + func (s *svc) getStorageProviderClient(_ context.Context, p *registry.ProviderInfo) (provider.ProviderAPIClient, error) { c, err := pool.GetStorageProviderServiceClient(p.Address) if err != nil { @@ -1060,6 +1091,35 @@ func (s *svc) findSpaces(ctx context.Context, ref *provider.Reference) ([]*regis return s.findProvider(ctx, listReq) } +func (s *svc) findSingleSpace(ctx context.Context, ref *provider.Reference) ([]*registry.ProviderInfo, error) { + switch { + case ref == nil: + return nil, errtypes.BadRequest("missing reference") + case ref.ResourceId != nil: + // no action needed in that case + case ref.Path != "": // TODO implement a mount path cache in the registry? + // nothing to do here either + default: + return nil, errtypes.BadRequest("invalid reference, at least path or id must be set") + } + + filters := map[string]string{ + "path": ref.Path, + "unique": "true", + } + if ref.ResourceId != nil { + filters["storage_id"] = ref.ResourceId.StorageId + filters["opaque_id"] = ref.ResourceId.OpaqueId + } + + listReq := ®istry.ListStorageProvidersRequest{ + Opaque: &typesv1beta1.Opaque{}, + } + sdk.EncodeOpaqueMap(listReq.Opaque, filters) + + return s.findProvider(ctx, listReq) +} + func (s *svc) findProvider(ctx context.Context, listReq *registry.ListStorageProvidersRequest) ([]*registry.ProviderInfo, error) { // lookup c, err := pool.GetStorageRegistryClient(s.c.StorageRegistryEndpoint)