X-Git-Url: https://git.arvados.org/arvados.git/blobdiff_plain/fa9a17bf1ea10d9130188730a1aa160e89daaa13..21c7799069b13380913d0dfdd9ecc441d3af7298:/lib/controller/federation/list.go diff --git a/lib/controller/federation/list.go b/lib/controller/federation/list.go index 6ee8133174..329066d1dc 100644 --- a/lib/controller/federation/list.go +++ b/lib/controller/federation/list.go @@ -27,6 +27,7 @@ func (conn *Conn) generated_CollectionList(ctx context.Context, options arvados. var needSort atomic.Value needSort.Store(false) err := conn.splitListRequest(ctx, options, func(ctx context.Context, _ string, backend arvados.API, options arvados.ListOptions) ([]string, error) { + options.ForwardedFor = conn.cluster.ClusterID + "-" + options.ForwardedFor cl, err := backend.CollectionList(ctx, options) if err != nil { return nil, err @@ -64,13 +65,13 @@ func (conn *Conn) generated_CollectionList(ctx context.Context, options arvados. // Call fn on one or more local/remote backends if opts indicates a // federation-wide list query, i.e.: // -// * There is at least one filter of the form -// ["uuid","in",[a,b,c,...]] or ["uuid","=",a] +// - There is at least one filter of the form +// ["uuid","in",[a,b,c,...]] or ["uuid","=",a] // -// * One or more of the supplied UUIDs (a,b,c,...) has a non-local -// prefix. +// - One or more of the supplied UUIDs (a,b,c,...) has a non-local +// prefix. // -// * There are no other filters +// - There are no other filters // // (If opts doesn't indicate a federation-wide list query, fn is just // called once with the local backend.) @@ -78,34 +79,46 @@ func (conn *Conn) generated_CollectionList(ctx context.Context, options arvados. // fn is called more than once only if the query meets the following // restrictions: // -// * Count=="none" +// - Count=="none" // -// * Limit<0 +// - Limit<0 // -// * len(Order)==0 +// - len(Order)==0 // -// * Each filter is either "uuid = ..." or "uuid in [...]". +// - Each filter is either "uuid = ..." or "uuid in [...]". // -// * The maximum possible response size (total number of objects that -// could potentially be matched by all of the specified filters) -// exceeds the local cluster's response page size limit. +// - The maximum possible response size (total number of objects +// that could potentially be matched by all of the specified +// filters) exceeds the local cluster's response page size limit. // // If the query involves multiple backends but doesn't meet these // restrictions, an error is returned without calling fn. // // Thus, the caller can assume that either: // -// * splitListRequest() returns an error, or +// - splitListRequest() returns an error, or // -// * fn is called exactly once, or +// - fn is called exactly once, or // -// * fn is called more than once, with options that satisfy the above -// restrictions. +// - fn is called more than once, with options that satisfy the above +// restrictions. // // Each call to fn indicates a single (local or remote) backend and a // corresponding options argument suitable for sending to that // backend. func (conn *Conn) splitListRequest(ctx context.Context, opts arvados.ListOptions, fn func(context.Context, string, arvados.API, arvados.ListOptions) ([]string, error)) error { + + if opts.BypassFederation || opts.ForwardedFor != "" { + // Client requested no federation. Pass through. + _, err := fn(ctx, conn.cluster.ClusterID, conn.local, opts) + return err + } + if opts.ClusterID != "" { + // Client explicitly selected cluster + _, err := fn(ctx, conn.cluster.ClusterID, conn.chooseBackend(opts.ClusterID), opts) + return err + } + cannotSplit := false var matchAllFilters map[string]bool for _, f := range opts.Filters { @@ -197,8 +210,8 @@ func (conn *Conn) splitListRequest(ctx context.Context, opts arvados.ListOptions if opts.Count != "none" { return httpErrorf(http.StatusBadRequest, "cannot execute federated list query unless count==\"none\"") } - if opts.Limit >= 0 || opts.Offset != 0 || len(opts.Order) > 0 { - return httpErrorf(http.StatusBadRequest, "cannot execute federated list query with limit, offset, or order parameter") + if (opts.Limit >= 0 && opts.Limit < int64(nUUIDs)) || opts.Offset != 0 || len(opts.Order) > 0 { + return httpErrorf(http.StatusBadRequest, "cannot execute federated list query with limit (%d) < nUUIDs (%d), offset (%d) > 0, or order (%v) parameter", opts.Limit, nUUIDs, opts.Offset, opts.Order) } if max := conn.cluster.API.MaxItemsPerResponse; nUUIDs > max { return httpErrorf(http.StatusBadRequest, "cannot execute federated list query because number of UUIDs (%d) exceeds page size limit %d", nUUIDs, max) @@ -242,7 +255,7 @@ func (conn *Conn) splitListRequest(ctx context.Context, opts arvados.ListOptions done, err := fn(ctx, clusterID, backend, remoteOpts) if err != nil { - errs <- httpErrorf(http.StatusBadGateway, err.Error()) + errs <- httpErrorf(http.StatusBadGateway, "%s", err.Error()) return } progress := false