17170: Add config keys to enable shell access for users/admins.
[arvados.git] / lib / controller / localdb / container_gateway.go
index ff3e3de5b08a55773979b8a75dc97a678a72af5c..b8d85516a2369366b6daed5d8aa064ed722f29e9 100644 (file)
@@ -34,28 +34,44 @@ func (conn *Conn) ContainerSSH(ctx context.Context, opts arvados.ContainerSSHOpt
        if err != nil {
                return
        }
-       ctxRoot := auth.NewContext(ctx, &auth.Credentials{Tokens: []string{conn.cluster.SystemRootToken}})
-       crs, err := conn.railsProxy.ContainerRequestList(ctxRoot, arvados.ListOptions{Limit: -1, Filters: []arvados.Filter{{"container_uuid", "=", opts.UUID}}})
+       ctr, err := conn.railsProxy.ContainerGet(ctx, arvados.GetOptions{UUID: opts.UUID})
        if err != nil {
                return
        }
-       for _, cr := range crs.Items {
-               if cr.ModifiedByUserUUID != user.UUID {
-                       err = httpserver.ErrorWithStatus(errors.New("permission denied: container is associated with requests submitted by other users"), http.StatusForbidden)
+       if !user.IsAdmin || !conn.cluster.Containers.ShellAccess.Admin {
+               if !conn.cluster.Containers.ShellAccess.User {
+                       err = httpserver.ErrorWithStatus(errors.New("shell access is disabled in config"), http.StatusServiceUnavailable)
+                       return
+               }
+               ctxRoot := auth.NewContext(ctx, &auth.Credentials{Tokens: []string{conn.cluster.SystemRootToken}})
+               var crs arvados.ContainerRequestList
+               crs, err = conn.railsProxy.ContainerRequestList(ctxRoot, arvados.ListOptions{Limit: -1, Filters: []arvados.Filter{{"container_uuid", "=", opts.UUID}}})
+               if err != nil {
+                       return
+               }
+               for _, cr := range crs.Items {
+                       if cr.ModifiedByUserUUID != user.UUID {
+                               err = httpserver.ErrorWithStatus(errors.New("permission denied: container is associated with requests submitted by other users"), http.StatusForbidden)
+                               return
+                       }
+               }
+               if crs.ItemsAvailable != len(crs.Items) {
+                       err = httpserver.ErrorWithStatus(errors.New("incomplete response while checking permission"), http.StatusInternalServerError)
                        return
                }
-       }
-       if crs.ItemsAvailable != len(crs.Items) {
-               err = httpserver.ErrorWithStatus(errors.New("incomplete response while checking permission"), http.StatusInternalServerError)
-               return
        }
 
-       ctr, err := conn.railsProxy.ContainerGet(ctx, arvados.GetOptions{UUID: opts.UUID})
-       if err != nil {
+       switch ctr.State {
+       case arvados.ContainerStateQueued, arvados.ContainerStateLocked:
+               err = httpserver.ErrorWithStatus(fmt.Errorf("gateway is not available, container is %s", strings.ToLower(string(ctr.State))), http.StatusServiceUnavailable)
                return
-       }
-       if ctr.GatewayAddress == "" || ctr.State != arvados.ContainerStateRunning {
-               err = httpserver.ErrorWithStatus(fmt.Errorf("gateway is not available, container is %s", strings.ToLower(string(ctr.State))), http.StatusBadGateway)
+       case arvados.ContainerStateRunning:
+               if ctr.GatewayAddress == "" {
+                       err = httpserver.ErrorWithStatus(errors.New("container is running but gateway is not available"), http.StatusServiceUnavailable)
+                       return
+               }
+       default:
+               err = httpserver.ErrorWithStatus(fmt.Errorf("gateway is not available, container is %s", strings.ToLower(string(ctr.State))), http.StatusGone)
                return
        }
        // crunch-run uses a self-signed / unverifiable TLS
@@ -96,6 +112,7 @@ func (conn *Conn) ContainerSSH(ctx context.Context, opts arvados.ContainerSSHOpt
                },
        })
        if err != nil {
+               err = httpserver.ErrorWithStatus(err, http.StatusBadGateway)
                return
        }
        if respondAuth == "" {