17944: Adds /_health/vocabulary health endpoint. Improves cache refreshing.
[arvados.git] / lib / controller / federation / conn.go
index 00523c7826a74331ea8c1560013c40aebca86f3d..7efbda8d127d523927f66a30ef6c5b4923811368 100644 (file)
@@ -22,6 +22,7 @@ import (
        "git.arvados.org/arvados.git/sdk/go/arvados"
        "git.arvados.org/arvados.git/sdk/go/auth"
        "git.arvados.org/arvados.git/sdk/go/ctxlog"
+       "git.arvados.org/arvados.git/sdk/go/health"
 )
 
 type Conn struct {
@@ -30,7 +31,7 @@ type Conn struct {
        remotes map[string]backend
 }
 
-func New(cluster *arvados.Cluster) *Conn {
+func New(cluster *arvados.Cluster, vocHealthFunc *health.Func) *Conn {
        local := localdb.NewConn(cluster)
        remotes := map[string]backend{}
        for id, remote := range cluster.RemoteClusters {
@@ -44,6 +45,8 @@ func New(cluster *arvados.Cluster) *Conn {
                remotes[id] = conn
        }
 
+       *vocHealthFunc = local.LastVocabularyError
+
        return &Conn{
                cluster: cluster,
                local:   local,
@@ -69,6 +72,9 @@ func saltedTokenProvider(local backend, remoteID string) rpc.TokenProvider {
                                tokens = append(tokens, salted)
                        case auth.ErrSalted:
                                tokens = append(tokens, token)
+                       case auth.ErrTokenFormat:
+                               // pass through unmodified (assume it's an OIDC access token)
+                               tokens = append(tokens, token)
                        case auth.ErrObsoleteToken:
                                ctx := auth.NewContext(ctx, &auth.Credentials{Tokens: []string{token}})
                                aca, err := local.APIClientAuthorizationCurrent(ctx, arvados.GetOptions{})
@@ -189,6 +195,10 @@ func (conn *Conn) ConfigGet(ctx context.Context) (json.RawMessage, error) {
        return json.RawMessage(buf.Bytes()), err
 }
 
+func (conn *Conn) VocabularyGet(ctx context.Context) (arvados.Vocabulary, error) {
+       return conn.chooseBackend(conn.cluster.ClusterID).VocabularyGet(ctx)
+}
+
 func (conn *Conn) Login(ctx context.Context, options arvados.LoginOptions) (arvados.LoginResponse, error) {
        if id := conn.cluster.Login.LoginCluster; id != "" && id != conn.cluster.ClusterID {
                // defer entire login procedure to designated cluster
@@ -259,13 +269,26 @@ func (conn *Conn) CollectionGet(ctx context.Context, options arvados.GetOptions)
                if err != nil {
                        return err
                }
-               // options.UUID is either hash+size or
-               // hash+size+hints; only hash+size need to
-               // match the computed PDH.
-               if pdh := arvados.PortableDataHash(c.ManifestText); pdh != options.UUID && !strings.HasPrefix(options.UUID, pdh+"+") {
-                       err = httpErrorf(http.StatusBadGateway, "bad portable data hash %q received from remote %q (expected %q)", pdh, remoteID, options.UUID)
-                       ctxlog.FromContext(ctx).Warn(err)
-                       return err
+               haveManifest := true
+               if options.Select != nil {
+                       haveManifest = false
+                       for _, s := range options.Select {
+                               if s == "manifest_text" {
+                                       haveManifest = true
+                                       break
+                               }
+                       }
+               }
+               if haveManifest {
+                       pdh := arvados.PortableDataHash(c.ManifestText)
+                       // options.UUID is either hash+size or
+                       // hash+size+hints; only hash+size need to
+                       // match the computed PDH.
+                       if pdh != options.UUID && !strings.HasPrefix(options.UUID, pdh+"+") {
+                               err = httpErrorf(http.StatusBadGateway, "bad portable data hash %q received from remote %q (expected %q)", pdh, remoteID, options.UUID)
+                               ctxlog.FromContext(ctx).Warn(err)
+                               return err
+                       }
                }
                if remoteID != "" {
                        c.ManifestText = rewriteManifest(c.ManifestText, remoteID)
@@ -336,6 +359,10 @@ func (conn *Conn) ContainerUnlock(ctx context.Context, options arvados.GetOption
        return conn.chooseBackend(options.UUID).ContainerUnlock(ctx, options)
 }
 
+func (conn *Conn) ContainerSSH(ctx context.Context, options arvados.ContainerSSHOptions) (arvados.ContainerSSHConnection, error) {
+       return conn.chooseBackend(options.UUID).ContainerSSH(ctx, options)
+}
+
 func (conn *Conn) ContainerRequestList(ctx context.Context, options arvados.ListOptions) (arvados.ContainerRequestList, error) {
        return conn.generated_ContainerRequestList(ctx, options)
 }
@@ -398,6 +425,73 @@ func (conn *Conn) ContainerRequestDelete(ctx context.Context, options arvados.De
        return conn.chooseBackend(options.UUID).ContainerRequestDelete(ctx, options)
 }
 
+func (conn *Conn) GroupCreate(ctx context.Context, options arvados.CreateOptions) (arvados.Group, error) {
+       return conn.chooseBackend(options.ClusterID).GroupCreate(ctx, options)
+}
+
+func (conn *Conn) GroupUpdate(ctx context.Context, options arvados.UpdateOptions) (arvados.Group, error) {
+       return conn.chooseBackend(options.UUID).GroupUpdate(ctx, options)
+}
+
+func (conn *Conn) GroupGet(ctx context.Context, options arvados.GetOptions) (arvados.Group, error) {
+       return conn.chooseBackend(options.UUID).GroupGet(ctx, options)
+}
+
+func (conn *Conn) GroupList(ctx context.Context, options arvados.ListOptions) (arvados.GroupList, error) {
+       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) {
+       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) {
+       return conn.chooseBackend(options.ClusterID).GroupShared(ctx, options)
+}
+
+func (conn *Conn) GroupDelete(ctx context.Context, options arvados.DeleteOptions) (arvados.Group, error) {
+       return conn.chooseBackend(options.UUID).GroupDelete(ctx, options)
+}
+
+func (conn *Conn) GroupTrash(ctx context.Context, options arvados.DeleteOptions) (arvados.Group, error) {
+       return conn.chooseBackend(options.UUID).GroupTrash(ctx, options)
+}
+
+func (conn *Conn) GroupUntrash(ctx context.Context, options arvados.UntrashOptions) (arvados.Group, error) {
+       return conn.chooseBackend(options.UUID).GroupUntrash(ctx, options)
+}
+
+func (conn *Conn) LinkCreate(ctx context.Context, options arvados.CreateOptions) (arvados.Link, error) {
+       return conn.chooseBackend(options.ClusterID).LinkCreate(ctx, options)
+}
+
+func (conn *Conn) LinkUpdate(ctx context.Context, options arvados.UpdateOptions) (arvados.Link, error) {
+       return conn.chooseBackend(options.UUID).LinkUpdate(ctx, options)
+}
+
+func (conn *Conn) LinkGet(ctx context.Context, options arvados.GetOptions) (arvados.Link, error) {
+       return conn.chooseBackend(options.UUID).LinkGet(ctx, options)
+}
+
+func (conn *Conn) LinkList(ctx context.Context, options arvados.ListOptions) (arvados.LinkList, error) {
+       return conn.generated_LinkList(ctx, options)
+}
+
+func (conn *Conn) LinkDelete(ctx context.Context, options arvados.DeleteOptions) (arvados.Link, error) {
+       return conn.chooseBackend(options.UUID).LinkDelete(ctx, options)
+}
+
 func (conn *Conn) SpecimenList(ctx context.Context, options arvados.ListOptions) (arvados.SpecimenList, error) {
        return conn.generated_SpecimenList(ctx, options)
 }
@@ -428,6 +522,7 @@ var userAttrsCachedFromLoginCluster = map[string]bool{
        "modified_at": true,
        "prefs":       true,
        "username":    true,
+       "kind":        true,
 
        "etag":                    false,
        "full_name":               false,
@@ -538,10 +633,6 @@ func (conn *Conn) UserUpdate(ctx context.Context, options arvados.UpdateOptions)
        return resp, err
 }
 
-func (conn *Conn) UserUpdateUUID(ctx context.Context, options arvados.UpdateUUIDOptions) (arvados.User, error) {
-       return conn.local.UserUpdateUUID(ctx, options)
-}
-
 func (conn *Conn) UserMerge(ctx context.Context, options arvados.UserMergeOptions) (arvados.User, error) {
        return conn.local.UserMerge(ctx, options)
 }