Merge branch '15781-multi-value-property-search'
[arvados.git] / lib / controller / federation / conn.go
index 1d8fa7e462cf96480adba03d7d814b1c246911c6..42083cb83df10918cdbc9f14869d0c2e49e51442 100644 (file)
@@ -17,12 +17,12 @@ import (
        "strings"
        "time"
 
-       "git.curoverse.com/arvados.git/lib/config"
-       "git.curoverse.com/arvados.git/lib/controller/localdb"
-       "git.curoverse.com/arvados.git/lib/controller/rpc"
-       "git.curoverse.com/arvados.git/sdk/go/arvados"
-       "git.curoverse.com/arvados.git/sdk/go/auth"
-       "git.curoverse.com/arvados.git/sdk/go/ctxlog"
+       "git.arvados.org/arvados.git/lib/config"
+       "git.arvados.org/arvados.git/lib/controller/localdb"
+       "git.arvados.org/arvados.git/lib/controller/rpc"
+       "git.arvados.org/arvados.git/sdk/go/arvados"
+       "git.arvados.org/arvados.git/sdk/go/auth"
+       "git.arvados.org/arvados.git/sdk/go/ctxlog"
 )
 
 type Conn struct {
@@ -38,7 +38,11 @@ func New(cluster *arvados.Cluster) *Conn {
                if !remote.Proxy {
                        continue
                }
-               remotes[id] = rpc.NewConn(id, &url.URL{Scheme: remote.Scheme, Host: remote.Host}, remote.Insecure, saltedTokenProvider(local, id))
+               conn := rpc.NewConn(id, &url.URL{Scheme: remote.Scheme, Host: remote.Host}, remote.Insecure, saltedTokenProvider(local, id))
+               // Older versions of controller rely on the Via header
+               // to detect loops.
+               conn.SendHeader = http.Header{"Via": {"HTTP/1.1 arvados-controller"}}
+               remotes[id] = conn
        }
 
        return &Conn{
@@ -116,8 +120,13 @@ func (conn *Conn) chooseBackend(id string) backend {
 // or "" for the local backend.
 //
 // A non-nil error means all backends failed.
-func (conn *Conn) tryLocalThenRemotes(ctx context.Context, fn func(context.Context, string, backend) error) error {
-       if err := fn(ctx, "", conn.local); err == nil || errStatus(err) != http.StatusNotFound {
+func (conn *Conn) tryLocalThenRemotes(ctx context.Context, forwardedFor string, fn func(context.Context, string, backend) error) error {
+       if err := fn(ctx, "", conn.local); err == nil || errStatus(err) != http.StatusNotFound || forwardedFor != "" {
+               // Note: forwardedFor != "" means this request came
+               // from a remote cluster, so we don't take a second
+               // hop. This avoids cycles, redundant calls to a
+               // mutually reachable remote, and use of double-salted
+               // tokens.
                return err
        }
 
@@ -198,10 +207,13 @@ func (conn *Conn) Login(ctx context.Context, options arvados.LoginOptions) (arva
                if err != nil {
                        return arvados.LoginResponse{}, fmt.Errorf("internal error getting redirect target: %s", err)
                }
-               target.RawQuery = url.Values{
+               params := url.Values{
                        "return_to": []string{options.ReturnTo},
-                       "remote":    []string{options.Remote},
-               }.Encode()
+               }
+               if options.Remote != "" {
+                       params.Set("remote", options.Remote)
+               }
+               target.RawQuery = params.Encode()
                return arvados.LoginResponse{
                        RedirectLocation: target.String(),
                }, nil
@@ -221,8 +233,10 @@ func (conn *Conn) CollectionGet(ctx context.Context, options arvados.GetOptions)
        } else {
                // UUID is a PDH
                first := make(chan arvados.Collection, 1)
-               err := conn.tryLocalThenRemotes(ctx, func(ctx context.Context, remoteID string, be backend) error {
-                       c, err := be.CollectionGet(ctx, options)
+               err := conn.tryLocalThenRemotes(ctx, options.ForwardedFor, func(ctx context.Context, remoteID string, be backend) error {
+                       remoteOpts := options
+                       remoteOpts.ForwardedFor = conn.cluster.ClusterID + "-" + options.ForwardedFor
+                       c, err := be.CollectionGet(ctx, remoteOpts)
                        if err != nil {
                                return err
                        }
@@ -337,11 +351,13 @@ var userAttrsCachedFromLoginCluster = map[string]bool{
        "prefs":                   true,
        "username":                true,
 
+       "etag":         false,
        "full_name":    false,
        "identity_url": false,
        "is_invited":   false,
        "owner_uuid":   false,
        "uuid":         false,
+       "writable_by":  false,
 }
 
 func (conn *Conn) UserList(ctx context.Context, options arvados.ListOptions) (arvados.UserList, error) {