return conn.generated_GroupList(ctx, options)
}
+var userUuidRe = regexp.MustCompile(`^[0-9a-z]{5}-tpzed-[0-9a-z]{15}$`)
+
func (conn *Conn) GroupContents(ctx context.Context, options arvados.GroupContentsOptions) (arvados.ObjectList, error) {
- return conn.chooseBackend(options.UUID).GroupContents(ctx, options)
+ if options.ClusterID != "" {
+ // explicitly selected cluster
+ return conn.chooseBackend(options.ClusterID).GroupContents(ctx, options)
+ } else if userUuidRe.MatchString(options.UUID) {
+ // user, get the things they own on the local cluster
+ return conn.local.GroupContents(ctx, options)
+ } else {
+ // a group, potentially want to make federated request
+ return conn.chooseBackend(options.UUID).GroupContents(ctx, options)
+ }
}
func (conn *Conn) GroupShared(ctx context.Context, options arvados.ListOptions) (arvados.GroupList, error) {
--- /dev/null
+// Copyright (C) The Arvados Authors. All rights reserved.
+//
+// SPDX-License-Identifier: AGPL-3.0
+
+package federation
+
+import (
+ "errors"
+
+ "git.arvados.org/arvados.git/sdk/go/arvados"
+ "git.arvados.org/arvados.git/sdk/go/arvadostest"
+ check "gopkg.in/check.v1"
+)
+
+var _ = check.Suite(&GroupSuite{})
+
+type GroupSuite struct {
+ FederationSuite
+}
+
+func makeConn() (*Conn, *arvadostest.APIStub, *arvadostest.APIStub) {
+ localAPIstub := &arvadostest.APIStub{Error: errors.New("No result")}
+ remoteAPIstub := &arvadostest.APIStub{Error: errors.New("No result")}
+ return &Conn{&arvados.Cluster{ClusterID: "local"}, localAPIstub, map[string]backend{"zzzzz": remoteAPIstub}}, localAPIstub, remoteAPIstub
+}
+
+func (s *UserSuite) TestGroupContents(c *check.C) {
+ conn, localAPIstub, remoteAPIstub := makeConn()
+ conn.GroupContents(s.ctx, arvados.GroupContentsOptions{UUID: "local-tpzed-xurymjxw79nv3jz"})
+ c.Check(len(localAPIstub.Calls(nil)), check.Equals, 1)
+ c.Check(len(remoteAPIstub.Calls(nil)), check.Equals, 0)
+
+ conn, localAPIstub, remoteAPIstub = makeConn()
+ conn.GroupContents(s.ctx, arvados.GroupContentsOptions{UUID: "zzzzz-tpzed-xurymjxw79nv3jz"})
+ c.Check(len(localAPIstub.Calls(nil)), check.Equals, 1)
+ c.Check(len(remoteAPIstub.Calls(nil)), check.Equals, 0)
+
+ conn, localAPIstub, remoteAPIstub = makeConn()
+ conn.GroupContents(s.ctx, arvados.GroupContentsOptions{UUID: "local-j7d0g-xurymjxw79nv3jz"})
+ c.Check(len(localAPIstub.Calls(nil)), check.Equals, 1)
+ c.Check(len(remoteAPIstub.Calls(nil)), check.Equals, 0)
+
+ conn, localAPIstub, remoteAPIstub = makeConn()
+ conn.GroupContents(s.ctx, arvados.GroupContentsOptions{UUID: "zzzzz-j7d0g-xurymjxw79nv3jz"})
+ c.Check(len(localAPIstub.Calls(nil)), check.Equals, 0)
+ c.Check(len(remoteAPIstub.Calls(nil)), check.Equals, 1)
+
+ conn, localAPIstub, remoteAPIstub = makeConn()
+ conn.GroupContents(s.ctx, arvados.GroupContentsOptions{UUID: "zzzzz-tpzed-xurymjxw79nv3jz", ClusterID: "zzzzz"})
+ c.Check(len(localAPIstub.Calls(nil)), check.Equals, 0)
+ c.Check(len(remoteAPIstub.Calls(nil)), check.Equals, 1)
+}
}
type GroupContentsOptions struct {
+ ClusterID string `json:"cluster_id"`
UUID string `json:"uuid,omitempty"`
Select []string `json:"select"`
Filters []Filter `json:"filters"`
# apply to each table being searched, not "groups".
load_limit_offset_order_params(fill_table_names: false)
+ if params['count'] == 'none' and @offset != 0 and (params['last_object_class'].nil? or params['last_object_class'].empty?)
+ # can't use offset without getting counts, so
+ # fall back to count=exact behavior.
+ params['count'] = 'exact'
+ set_count_none = true
+ end
+
# Trick apply_where_limit_order_params into applying suitable
# per-table values. *_all are the real ones we'll apply to the
# aggregate set.
seen_last_class = false
klasses.each do |klass|
- # if current klass is same as params['last_object_class'], mark that fact
+ # check if current klass is same as params['last_object_class']
seen_last_class = true if((params['count'].andand.==('none')) and
(params['last_object_class'].nil? or
params['last_object_class'].empty? or
# if klasses are specified, skip all other klass types
next if wanted_klasses.any? and !wanted_klasses.include?(klass.to_s)
- # don't reprocess klass types that were already seen
+ # if specified, and count=none, then only look at the klass in
+ # last_object_class.
+ # for whatever reason, this parameter exists separately from 'wanted_klasses'
next if params['count'] == 'none' and !seen_last_class
# don't process rest of object types if we already have needed number of objects
if params['exclude_home_project']
@objects = exclude_home @objects, klass
end
- if params['count'] == 'none'
- # The call to object_list below will not populate :items_available in
- # its response, because count is disabled. Save @objects length (does
- # not require another db query) so that @offset (if set) is handled
- # correctly.
- countless_items_available = @objects.length
- end
+ # Adjust the limit based on number of objects fetched so far
klass_limit = limit_all - all_objects.count
@limit = klass_limit
apply_where_limit_order_params klass
+
+ # This actually fetches the objects
klass_object_list = object_list(model_class: klass)
- if params['count'] != 'none'
- klass_items_available = klass_object_list[:items_available] || 0
- else
- # klass_object_list[:items_available] is not populated
- klass_items_available = countless_items_available
- end
+
+ # If count=none, :items_available will be nil, and offset is
+ # required to be 0.
+ klass_items_available = klass_object_list[:items_available] || 0
@items_available += klass_items_available
@offset = [@offset - klass_items_available, 0].max
+
+ # Add objects to the list of objects to be returned.
all_objects += klass_object_list[:items]
if klass_object_list[:limit] < klass_limit
@extra_included = included_by_uuid.values
end
+ if set_count_none
+ params['count'] = 'none'
+ end
+
@objects = all_objects
@limit = limit_all
@offset = offset_all
self.project_object = self.api.users().get(
uuid=self.project_uuid).execute(num_retries=self.num_retries)
# do this in 2 steps until #17424 is fixed
- contents = arvados.util.list_all(self.api.groups().contents,
- self.num_retries,
- uuid=self.project_uuid,
- filters=[["uuid", "is_a", "arvados#group"],
- ["groups.group_class", "in", ["project","filter"]]])
- contents.extend(arvados.util.list_all(self.api.groups().contents,
- self.num_retries,
- uuid=self.project_uuid,
- filters=[["uuid", "is_a", "arvados#collection"]]))
+ contents = list(arvados.util.keyset_list_all(self.api.groups().contents,
+ order_key="uuid",
+ num_retries=self.num_retries,
+ uuid=self.project_uuid,
+ filters=[["uuid", "is_a", "arvados#group"],
+ ["groups.group_class", "in", ["project","filter"]]]))
+ contents.extend(arvados.util.keyset_list_all(self.api.groups().contents,
+ order_key="uuid",
+ num_retries=self.num_retries,
+ uuid=self.project_uuid,
+ filters=[["uuid", "is_a", "arvados#collection"]]))
# end with llfuse.lock_released, re-acquire lock
objects[r["uuid"]] = r
root_owners.add(r["uuid"])
else:
- all_projects = arvados.util.list_all(
- self.api.groups().list, self.num_retries,
+ all_projects = list(arvados.util.keyset_list_all(
+ self.api.groups().list,
+ order_key="uuid",
+ num_retries=self.num_retries,
filters=[['group_class','in',['project','filter']]],
- select=["uuid", "owner_uuid"])
+ select=["uuid", "owner_uuid"]))
for ob in all_projects:
objects[ob['uuid']] = ob
roots.append(ob['uuid'])
root_owners.add(ob['owner_uuid'])
- lusers = arvados.util.list_all(
- self.api.users().list, self.num_retries,
+ lusers = arvados.util.keyset_list_all(
+ self.api.users().list,
+ order_key="uuid",
+ num_retries=self.num_retries,
filters=[['uuid','in', list(root_owners)]])
- lgroups = arvados.util.list_all(
- self.api.groups().list, self.num_retries,
+ lgroups = arvados.util.keyset_list_all(
+ self.api.groups().list,
+ order_key="uuid",
+ num_retries=self.num_retries,
filters=[['uuid','in', list(root_owners)+roots]])
for l in lusers: