21123: Add container_requests/{uuid}/container_status endpoint.
authorTom Clegg <tom@curii.com>
Tue, 5 Mar 2024 00:02:44 +0000 (19:02 -0500)
committerTom Clegg <tom@curii.com>
Tue, 5 Mar 2024 22:40:18 +0000 (17:40 -0500)
Arvados-DCO-1.1-Signed-off-by: Tom Clegg <tom@curii.com>

doc/api/methods/container_requests.html.textile.liquid
lib/controller/federation/conn.go
lib/controller/localdb/container_request.go
lib/controller/router/router.go
lib/controller/rpc/conn.go
sdk/go/arvados/api.go
sdk/go/arvados/container.go
sdk/go/arvadostest/api.go
services/api/config/routes.rb

index c108c32808877b76e8d6af647c1dd5da63d66bbc..770b56b6976b1630b579ecb7a293aaeb661ff100 100644 (file)
@@ -224,6 +224,26 @@ Setting the priority of a committed container_request to 0 may cancel a running
 See "Canceling a container request":{{site.baseurl}}/api/methods/container_requests.html#cancel_container for further details.
 {% include 'notebox_end' %}
 
+h3(#container_status). container_status
+
+Get container status.
+
+table(table table-bordered table-condensed).
+|_. Argument |_. Type |_. Description |_. Location |
+{background:#ccffcc}.|uuid|string|The UUID of the container request in question.|path|
+
+Example request: @GET /arvados/v1/container_requests/zzzzz-xvdhp-0123456789abcde/container_status@
+
+Response attributes:
+
+table(table table-bordered table-condensed).
+|_. Attribute|_. Type|_. Description|_. Examples|
+|uuid|string|The UUID of the container assigned to this request.||
+|state|string|The state of the container assigned to this request (see "container resource attributes":containers.html).||
+|scheduling_status|string|A brief explanation of the container's status in the dispatch queue. Empty if scheduling is not applicable, e.g., the container is running or finished.|@waiting for cloud resources: queue position 3@
+@creating new instance@
+@preparing runtime environment@|
+
 h3(#log). log
 
 Get container log data using WebDAV methods.
index c5facdc7d9cf58fd2dbfa01091620a0a528e2381..949cc56dd24cc34b71a8f7ef8ea7ac1d15df6e29 100644 (file)
@@ -510,6 +510,10 @@ func (conn *Conn) ContainerRequestDelete(ctx context.Context, options arvados.De
        return conn.chooseBackend(options.UUID).ContainerRequestDelete(ctx, options)
 }
 
+func (conn *Conn) ContainerRequestContainerStatus(ctx context.Context, options arvados.GetOptions) (arvados.ContainerStatus, error) {
+       return conn.chooseBackend(options.UUID).ContainerRequestContainerStatus(ctx, options)
+}
+
 func (conn *Conn) ContainerRequestLog(ctx context.Context, options arvados.ContainerLogOptions) (http.Handler, error) {
        return conn.chooseBackend(options.UUID).ContainerRequestLog(ctx, options)
 }
index 49e21840ea206f69684738e2f9aec98f0f6c2fd3..0234ee8fa6e618fa9d095c938cb2721ae69bda90 100644 (file)
@@ -6,8 +6,15 @@ package localdb
 
 import (
        "context"
+       "encoding/json"
+       "fmt"
+       "net/http"
+       "net/url"
 
+       "git.arvados.org/arvados.git/lib/dispatchcloud/scheduler"
        "git.arvados.org/arvados.git/sdk/go/arvados"
+       "git.arvados.org/arvados.git/sdk/go/auth"
+       "git.arvados.org/arvados.git/sdk/go/httpserver"
 )
 
 // ContainerRequestCreate defers to railsProxy for everything except
@@ -54,3 +61,87 @@ func (conn *Conn) ContainerRequestDelete(ctx context.Context, opts arvados.Delet
        conn.logActivity(ctx)
        return conn.railsProxy.ContainerRequestDelete(ctx, opts)
 }
+
+func (conn *Conn) ContainerRequestContainerStatus(ctx context.Context, opts arvados.GetOptions) (arvados.ContainerStatus, error) {
+       conn.logActivity(ctx)
+       var ret arvados.ContainerStatus
+       cr, err := conn.railsProxy.ContainerRequestGet(ctx, arvados.GetOptions{UUID: opts.UUID, Select: []string{"uuid", "container_uuid", "log_uuid"}})
+       if err != nil {
+               return ret, err
+       }
+       if cr.ContainerUUID == "" {
+               ret.SchedulingStatus = "no container assigned"
+               return ret, nil
+       }
+       // We use admin credentials to get the container record so we
+       // don't get an error when we're in a race with auto-retry and
+       // the container became user-unreadable since we fetched the
+       // CR above.
+       ctxRoot := auth.NewContext(ctx, &auth.Credentials{Tokens: []string{conn.cluster.SystemRootToken}})
+       ctr, err := conn.railsProxy.ContainerGet(ctxRoot, arvados.GetOptions{UUID: cr.ContainerUUID, Select: []string{"uuid", "state", "priority"}})
+       if err != nil {
+               return ret, err
+       }
+       ret.UUID = ctr.UUID
+       ret.State = ctr.State
+       if ctr.State != arvados.ContainerStateQueued && ctr.State != arvados.ContainerStateLocked {
+               // Scheduling status is not a thing once the container
+               // is in running state.
+               return ret, nil
+       }
+       var lastErr error
+       for dispatchurl := range conn.cluster.Services.DispatchCloud.InternalURLs {
+               baseurl := url.URL(dispatchurl)
+               apiurl, err := baseurl.Parse("/arvados/v1/dispatch/container?container_uuid=" + cr.ContainerUUID)
+               if err != nil {
+                       lastErr = err
+                       continue
+               }
+               req, err := http.NewRequestWithContext(ctx, http.MethodGet, apiurl.String(), nil)
+               if err != nil {
+                       lastErr = err
+                       continue
+               }
+               req.Header.Set("Authorization", "Bearer "+conn.cluster.ManagementToken)
+               resp, err := http.DefaultClient.Do(req)
+               if err != nil {
+                       lastErr = fmt.Errorf("error getting status from dispatcher: %w", err)
+                       continue
+               }
+               if resp.StatusCode == http.StatusNotFound {
+                       continue
+               } else if resp.StatusCode != http.StatusOK {
+                       lastErr = fmt.Errorf("error getting status from dispatcher: %s", resp.Status)
+                       continue
+               }
+               var qent scheduler.QueueEnt
+               err = json.NewDecoder(resp.Body).Decode(&qent)
+               if err != nil {
+                       lastErr = err
+                       continue
+               }
+               ret.State = qent.Container.State // Prefer dispatcher's view of state if not equal to ctr.State
+               ret.SchedulingStatus = qent.SchedulingStatus
+               return ret, nil
+       }
+       if lastErr != nil {
+               // If we got a non-nil error from a dispatchcloud
+               // service, and the container state suggests
+               // dispatchcloud should know about it, then we return
+               // an error so the client knows to retry.
+               return ret, httpserver.ErrorWithStatus(lastErr, http.StatusBadGateway)
+       }
+       // All running dispatchcloud services confirm they don't have
+       // this container (the dispatcher hasn't yet noticed it
+       // appearing in the queue) or there are no dispatchcloud
+       // services configured. Either way, all we can say is that
+       // it's queued.
+       if ctr.State == arvados.ContainerStateQueued && ctr.Priority < 1 {
+               // If it hasn't been picked up by a dispatcher
+               // already, it won't be -- it's just on hold.
+               // Scheduling status does not apply.
+               return ret, nil
+       }
+       ret.SchedulingStatus = "waiting for dispatch"
+       return ret, nil
+}
index d39f493a956b21d66b38182addb36f9462d57736..054bcffaf7ecf33b12965bb8e0d0be2d9590e1e0 100644 (file)
@@ -318,6 +318,13 @@ func (rtr *router) addRoutes() {
                                return rtr.backend.ContainerRequestDelete(ctx, *opts.(*arvados.DeleteOptions))
                        },
                },
+               {
+                       arvados.EndpointContainerRequestContainerStatus,
+                       func() interface{} { return &arvados.GetOptions{} },
+                       func(ctx context.Context, opts interface{}) (interface{}, error) {
+                               return rtr.backend.ContainerRequestContainerStatus(ctx, *opts.(*arvados.GetOptions))
+                       },
+               },
                {
                        arvados.EndpointContainerRequestLog,
                        func() interface{} { return &arvados.ContainerLogOptions{} },
index 9f518d9c7a91027a0ddc6552a341455b14b5f256..c6be679a256cb2e860d5ce179646e3378219d1c6 100644 (file)
@@ -529,6 +529,13 @@ func (conn *Conn) ContainerRequestDelete(ctx context.Context, options arvados.De
        return resp, err
 }
 
+func (conn *Conn) ContainerRequestContainerStatus(ctx context.Context, options arvados.GetOptions) (arvados.ContainerStatus, error) {
+       ep := arvados.EndpointContainerRequestContainerStatus
+       var resp arvados.ContainerStatus
+       err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
+       return resp, err
+}
+
 func (conn *Conn) ContainerRequestLog(ctx context.Context, options arvados.ContainerLogOptions) (resp http.Handler, err error) {
        proxy := &httputil.ReverseProxy{
                Transport: conn.httpClient.Transport,
index e7310818f7d745b55fda3ceed59bf2438bfab9e1..c3d0ea8aef676b3d3c57ce0bfbbcbe129b7689ac 100644 (file)
@@ -23,90 +23,91 @@ type APIEndpoint struct {
 }
 
 var (
-       EndpointConfigGet                     = APIEndpoint{"GET", "arvados/v1/config", ""}
-       EndpointVocabularyGet                 = APIEndpoint{"GET", "arvados/v1/vocabulary", ""}
-       EndpointDiscoveryDocument             = APIEndpoint{"GET", "discovery/v1/apis/arvados/v1/rest", ""}
-       EndpointLogin                         = APIEndpoint{"GET", "login", ""}
-       EndpointLogout                        = APIEndpoint{"GET", "logout", ""}
-       EndpointAuthorizedKeyCreate           = APIEndpoint{"POST", "arvados/v1/authorized_keys", "authorized_key"}
-       EndpointAuthorizedKeyUpdate           = APIEndpoint{"PATCH", "arvados/v1/authorized_keys/{uuid}", "authorized_key"}
-       EndpointAuthorizedKeyGet              = APIEndpoint{"GET", "arvados/v1/authorized_keys/{uuid}", ""}
-       EndpointAuthorizedKeyList             = APIEndpoint{"GET", "arvados/v1/authorized_keys", ""}
-       EndpointAuthorizedKeyDelete           = APIEndpoint{"DELETE", "arvados/v1/authorized_keys/{uuid}", ""}
-       EndpointCollectionCreate              = APIEndpoint{"POST", "arvados/v1/collections", "collection"}
-       EndpointCollectionUpdate              = APIEndpoint{"PATCH", "arvados/v1/collections/{uuid}", "collection"}
-       EndpointCollectionGet                 = APIEndpoint{"GET", "arvados/v1/collections/{uuid}", ""}
-       EndpointCollectionList                = APIEndpoint{"GET", "arvados/v1/collections", ""}
-       EndpointCollectionProvenance          = APIEndpoint{"GET", "arvados/v1/collections/{uuid}/provenance", ""}
-       EndpointCollectionUsedBy              = APIEndpoint{"GET", "arvados/v1/collections/{uuid}/used_by", ""}
-       EndpointCollectionDelete              = APIEndpoint{"DELETE", "arvados/v1/collections/{uuid}", ""}
-       EndpointCollectionTrash               = APIEndpoint{"POST", "arvados/v1/collections/{uuid}/trash", ""}
-       EndpointCollectionUntrash             = APIEndpoint{"POST", "arvados/v1/collections/{uuid}/untrash", ""}
-       EndpointSpecimenCreate                = APIEndpoint{"POST", "arvados/v1/specimens", "specimen"}
-       EndpointSpecimenUpdate                = APIEndpoint{"PATCH", "arvados/v1/specimens/{uuid}", "specimen"}
-       EndpointSpecimenGet                   = APIEndpoint{"GET", "arvados/v1/specimens/{uuid}", ""}
-       EndpointSpecimenList                  = APIEndpoint{"GET", "arvados/v1/specimens", ""}
-       EndpointSpecimenDelete                = APIEndpoint{"DELETE", "arvados/v1/specimens/{uuid}", ""}
-       EndpointContainerCreate               = APIEndpoint{"POST", "arvados/v1/containers", "container"}
-       EndpointContainerUpdate               = APIEndpoint{"PATCH", "arvados/v1/containers/{uuid}", "container"}
-       EndpointContainerPriorityUpdate       = APIEndpoint{"POST", "arvados/v1/containers/{uuid}/update_priority", "container"}
-       EndpointContainerGet                  = APIEndpoint{"GET", "arvados/v1/containers/{uuid}", ""}
-       EndpointContainerList                 = APIEndpoint{"GET", "arvados/v1/containers", ""}
-       EndpointContainerDelete               = APIEndpoint{"DELETE", "arvados/v1/containers/{uuid}", ""}
-       EndpointContainerLock                 = APIEndpoint{"POST", "arvados/v1/containers/{uuid}/lock", ""}
-       EndpointContainerUnlock               = APIEndpoint{"POST", "arvados/v1/containers/{uuid}/unlock", ""}
-       EndpointContainerSSH                  = APIEndpoint{"POST", "arvados/v1/containers/{uuid}/ssh", ""}
-       EndpointContainerSSHCompat            = APIEndpoint{"POST", "arvados/v1/connect/{uuid}/ssh", ""} // for compatibility with arvados <2.7
-       EndpointContainerGatewayTunnel        = APIEndpoint{"POST", "arvados/v1/containers/{uuid}/gateway_tunnel", ""}
-       EndpointContainerGatewayTunnelCompat  = APIEndpoint{"POST", "arvados/v1/connect/{uuid}/gateway_tunnel", ""} // for compatibility with arvados <2.7
-       EndpointContainerRequestCreate        = APIEndpoint{"POST", "arvados/v1/container_requests", "container_request"}
-       EndpointContainerRequestUpdate        = APIEndpoint{"PATCH", "arvados/v1/container_requests/{uuid}", "container_request"}
-       EndpointContainerRequestGet           = APIEndpoint{"GET", "arvados/v1/container_requests/{uuid}", ""}
-       EndpointContainerRequestList          = APIEndpoint{"GET", "arvados/v1/container_requests", ""}
-       EndpointContainerRequestDelete        = APIEndpoint{"DELETE", "arvados/v1/container_requests/{uuid}", ""}
-       EndpointContainerRequestLog           = APIEndpoint{"GET", "arvados/v1/container_requests/{uuid}/log{path:|/.*}", ""}
-       EndpointGroupCreate                   = APIEndpoint{"POST", "arvados/v1/groups", "group"}
-       EndpointGroupUpdate                   = APIEndpoint{"PATCH", "arvados/v1/groups/{uuid}", "group"}
-       EndpointGroupGet                      = APIEndpoint{"GET", "arvados/v1/groups/{uuid}", ""}
-       EndpointGroupList                     = APIEndpoint{"GET", "arvados/v1/groups", ""}
-       EndpointGroupContents                 = APIEndpoint{"GET", "arvados/v1/groups/contents", ""}
-       EndpointGroupContentsUUIDInPath       = APIEndpoint{"GET", "arvados/v1/groups/{uuid}/contents", ""} // Alternative HTTP route; client-side code should always use EndpointGroupContents instead
-       EndpointGroupShared                   = APIEndpoint{"GET", "arvados/v1/groups/shared", ""}
-       EndpointGroupDelete                   = APIEndpoint{"DELETE", "arvados/v1/groups/{uuid}", ""}
-       EndpointGroupTrash                    = APIEndpoint{"POST", "arvados/v1/groups/{uuid}/trash", ""}
-       EndpointGroupUntrash                  = APIEndpoint{"POST", "arvados/v1/groups/{uuid}/untrash", ""}
-       EndpointLinkCreate                    = APIEndpoint{"POST", "arvados/v1/links", "link"}
-       EndpointLinkUpdate                    = APIEndpoint{"PATCH", "arvados/v1/links/{uuid}", "link"}
-       EndpointLinkGet                       = APIEndpoint{"GET", "arvados/v1/links/{uuid}", ""}
-       EndpointLinkList                      = APIEndpoint{"GET", "arvados/v1/links", ""}
-       EndpointLinkDelete                    = APIEndpoint{"DELETE", "arvados/v1/links/{uuid}", ""}
-       EndpointLogCreate                     = APIEndpoint{"POST", "arvados/v1/logs", "log"}
-       EndpointLogUpdate                     = APIEndpoint{"PATCH", "arvados/v1/logs/{uuid}", "log"}
-       EndpointLogGet                        = APIEndpoint{"GET", "arvados/v1/logs/{uuid}", ""}
-       EndpointLogList                       = APIEndpoint{"GET", "arvados/v1/logs", ""}
-       EndpointLogDelete                     = APIEndpoint{"DELETE", "arvados/v1/logs/{uuid}", ""}
-       EndpointSysTrashSweep                 = APIEndpoint{"POST", "sys/trash_sweep", ""}
-       EndpointUserActivate                  = APIEndpoint{"POST", "arvados/v1/users/{uuid}/activate", ""}
-       EndpointUserCreate                    = APIEndpoint{"POST", "arvados/v1/users", "user"}
-       EndpointUserCurrent                   = APIEndpoint{"GET", "arvados/v1/users/current", ""}
-       EndpointUserDelete                    = APIEndpoint{"DELETE", "arvados/v1/users/{uuid}", ""}
-       EndpointUserGet                       = APIEndpoint{"GET", "arvados/v1/users/{uuid}", ""}
-       EndpointUserGetCurrent                = APIEndpoint{"GET", "arvados/v1/users/current", ""}
-       EndpointUserGetSystem                 = APIEndpoint{"GET", "arvados/v1/users/system", ""}
-       EndpointUserList                      = APIEndpoint{"GET", "arvados/v1/users", ""}
-       EndpointUserMerge                     = APIEndpoint{"POST", "arvados/v1/users/merge", ""}
-       EndpointUserSetup                     = APIEndpoint{"POST", "arvados/v1/users/setup", "user"}
-       EndpointUserSystem                    = APIEndpoint{"GET", "arvados/v1/users/system", ""}
-       EndpointUserUnsetup                   = APIEndpoint{"POST", "arvados/v1/users/{uuid}/unsetup", ""}
-       EndpointUserUpdate                    = APIEndpoint{"PATCH", "arvados/v1/users/{uuid}", "user"}
-       EndpointUserBatchUpdate               = APIEndpoint{"PATCH", "arvados/v1/users/batch_update", ""}
-       EndpointUserAuthenticate              = APIEndpoint{"POST", "arvados/v1/users/authenticate", ""}
-       EndpointAPIClientAuthorizationCurrent = APIEndpoint{"GET", "arvados/v1/api_client_authorizations/current", ""}
-       EndpointAPIClientAuthorizationCreate  = APIEndpoint{"POST", "arvados/v1/api_client_authorizations", "api_client_authorization"}
-       EndpointAPIClientAuthorizationUpdate  = APIEndpoint{"PUT", "arvados/v1/api_client_authorizations/{uuid}", "api_client_authorization"}
-       EndpointAPIClientAuthorizationList    = APIEndpoint{"GET", "arvados/v1/api_client_authorizations", ""}
-       EndpointAPIClientAuthorizationDelete  = APIEndpoint{"DELETE", "arvados/v1/api_client_authorizations/{uuid}", ""}
-       EndpointAPIClientAuthorizationGet     = APIEndpoint{"GET", "arvados/v1/api_client_authorizations/{uuid}", ""}
+       EndpointConfigGet                       = APIEndpoint{"GET", "arvados/v1/config", ""}
+       EndpointVocabularyGet                   = APIEndpoint{"GET", "arvados/v1/vocabulary", ""}
+       EndpointDiscoveryDocument               = APIEndpoint{"GET", "discovery/v1/apis/arvados/v1/rest", ""}
+       EndpointLogin                           = APIEndpoint{"GET", "login", ""}
+       EndpointLogout                          = APIEndpoint{"GET", "logout", ""}
+       EndpointAuthorizedKeyCreate             = APIEndpoint{"POST", "arvados/v1/authorized_keys", "authorized_key"}
+       EndpointAuthorizedKeyUpdate             = APIEndpoint{"PATCH", "arvados/v1/authorized_keys/{uuid}", "authorized_key"}
+       EndpointAuthorizedKeyGet                = APIEndpoint{"GET", "arvados/v1/authorized_keys/{uuid}", ""}
+       EndpointAuthorizedKeyList               = APIEndpoint{"GET", "arvados/v1/authorized_keys", ""}
+       EndpointAuthorizedKeyDelete             = APIEndpoint{"DELETE", "arvados/v1/authorized_keys/{uuid}", ""}
+       EndpointCollectionCreate                = APIEndpoint{"POST", "arvados/v1/collections", "collection"}
+       EndpointCollectionUpdate                = APIEndpoint{"PATCH", "arvados/v1/collections/{uuid}", "collection"}
+       EndpointCollectionGet                   = APIEndpoint{"GET", "arvados/v1/collections/{uuid}", ""}
+       EndpointCollectionList                  = APIEndpoint{"GET", "arvados/v1/collections", ""}
+       EndpointCollectionProvenance            = APIEndpoint{"GET", "arvados/v1/collections/{uuid}/provenance", ""}
+       EndpointCollectionUsedBy                = APIEndpoint{"GET", "arvados/v1/collections/{uuid}/used_by", ""}
+       EndpointCollectionDelete                = APIEndpoint{"DELETE", "arvados/v1/collections/{uuid}", ""}
+       EndpointCollectionTrash                 = APIEndpoint{"POST", "arvados/v1/collections/{uuid}/trash", ""}
+       EndpointCollectionUntrash               = APIEndpoint{"POST", "arvados/v1/collections/{uuid}/untrash", ""}
+       EndpointSpecimenCreate                  = APIEndpoint{"POST", "arvados/v1/specimens", "specimen"}
+       EndpointSpecimenUpdate                  = APIEndpoint{"PATCH", "arvados/v1/specimens/{uuid}", "specimen"}
+       EndpointSpecimenGet                     = APIEndpoint{"GET", "arvados/v1/specimens/{uuid}", ""}
+       EndpointSpecimenList                    = APIEndpoint{"GET", "arvados/v1/specimens", ""}
+       EndpointSpecimenDelete                  = APIEndpoint{"DELETE", "arvados/v1/specimens/{uuid}", ""}
+       EndpointContainerCreate                 = APIEndpoint{"POST", "arvados/v1/containers", "container"}
+       EndpointContainerUpdate                 = APIEndpoint{"PATCH", "arvados/v1/containers/{uuid}", "container"}
+       EndpointContainerPriorityUpdate         = APIEndpoint{"POST", "arvados/v1/containers/{uuid}/update_priority", "container"}
+       EndpointContainerGet                    = APIEndpoint{"GET", "arvados/v1/containers/{uuid}", ""}
+       EndpointContainerList                   = APIEndpoint{"GET", "arvados/v1/containers", ""}
+       EndpointContainerDelete                 = APIEndpoint{"DELETE", "arvados/v1/containers/{uuid}", ""}
+       EndpointContainerLock                   = APIEndpoint{"POST", "arvados/v1/containers/{uuid}/lock", ""}
+       EndpointContainerUnlock                 = APIEndpoint{"POST", "arvados/v1/containers/{uuid}/unlock", ""}
+       EndpointContainerSSH                    = APIEndpoint{"POST", "arvados/v1/containers/{uuid}/ssh", ""}
+       EndpointContainerSSHCompat              = APIEndpoint{"POST", "arvados/v1/connect/{uuid}/ssh", ""} // for compatibility with arvados <2.7
+       EndpointContainerGatewayTunnel          = APIEndpoint{"POST", "arvados/v1/containers/{uuid}/gateway_tunnel", ""}
+       EndpointContainerGatewayTunnelCompat    = APIEndpoint{"POST", "arvados/v1/connect/{uuid}/gateway_tunnel", ""} // for compatibility with arvados <2.7
+       EndpointContainerRequestCreate          = APIEndpoint{"POST", "arvados/v1/container_requests", "container_request"}
+       EndpointContainerRequestUpdate          = APIEndpoint{"PATCH", "arvados/v1/container_requests/{uuid}", "container_request"}
+       EndpointContainerRequestGet             = APIEndpoint{"GET", "arvados/v1/container_requests/{uuid}", ""}
+       EndpointContainerRequestList            = APIEndpoint{"GET", "arvados/v1/container_requests", ""}
+       EndpointContainerRequestDelete          = APIEndpoint{"DELETE", "arvados/v1/container_requests/{uuid}", ""}
+       EndpointContainerRequestContainerStatus = APIEndpoint{"GET", "arvados/v1/container_requests/{uuid}/container_status", ""}
+       EndpointContainerRequestLog             = APIEndpoint{"GET", "arvados/v1/container_requests/{uuid}/log{path:|/.*}", ""}
+       EndpointGroupCreate                     = APIEndpoint{"POST", "arvados/v1/groups", "group"}
+       EndpointGroupUpdate                     = APIEndpoint{"PATCH", "arvados/v1/groups/{uuid}", "group"}
+       EndpointGroupGet                        = APIEndpoint{"GET", "arvados/v1/groups/{uuid}", ""}
+       EndpointGroupList                       = APIEndpoint{"GET", "arvados/v1/groups", ""}
+       EndpointGroupContents                   = APIEndpoint{"GET", "arvados/v1/groups/contents", ""}
+       EndpointGroupContentsUUIDInPath         = APIEndpoint{"GET", "arvados/v1/groups/{uuid}/contents", ""} // Alternative HTTP route; client-side code should always use EndpointGroupContents instead
+       EndpointGroupShared                     = APIEndpoint{"GET", "arvados/v1/groups/shared", ""}
+       EndpointGroupDelete                     = APIEndpoint{"DELETE", "arvados/v1/groups/{uuid}", ""}
+       EndpointGroupTrash                      = APIEndpoint{"POST", "arvados/v1/groups/{uuid}/trash", ""}
+       EndpointGroupUntrash                    = APIEndpoint{"POST", "arvados/v1/groups/{uuid}/untrash", ""}
+       EndpointLinkCreate                      = APIEndpoint{"POST", "arvados/v1/links", "link"}
+       EndpointLinkUpdate                      = APIEndpoint{"PATCH", "arvados/v1/links/{uuid}", "link"}
+       EndpointLinkGet                         = APIEndpoint{"GET", "arvados/v1/links/{uuid}", ""}
+       EndpointLinkList                        = APIEndpoint{"GET", "arvados/v1/links", ""}
+       EndpointLinkDelete                      = APIEndpoint{"DELETE", "arvados/v1/links/{uuid}", ""}
+       EndpointLogCreate                       = APIEndpoint{"POST", "arvados/v1/logs", "log"}
+       EndpointLogUpdate                       = APIEndpoint{"PATCH", "arvados/v1/logs/{uuid}", "log"}
+       EndpointLogGet                          = APIEndpoint{"GET", "arvados/v1/logs/{uuid}", ""}
+       EndpointLogList                         = APIEndpoint{"GET", "arvados/v1/logs", ""}
+       EndpointLogDelete                       = APIEndpoint{"DELETE", "arvados/v1/logs/{uuid}", ""}
+       EndpointSysTrashSweep                   = APIEndpoint{"POST", "sys/trash_sweep", ""}
+       EndpointUserActivate                    = APIEndpoint{"POST", "arvados/v1/users/{uuid}/activate", ""}
+       EndpointUserCreate                      = APIEndpoint{"POST", "arvados/v1/users", "user"}
+       EndpointUserCurrent                     = APIEndpoint{"GET", "arvados/v1/users/current", ""}
+       EndpointUserDelete                      = APIEndpoint{"DELETE", "arvados/v1/users/{uuid}", ""}
+       EndpointUserGet                         = APIEndpoint{"GET", "arvados/v1/users/{uuid}", ""}
+       EndpointUserGetCurrent                  = APIEndpoint{"GET", "arvados/v1/users/current", ""}
+       EndpointUserGetSystem                   = APIEndpoint{"GET", "arvados/v1/users/system", ""}
+       EndpointUserList                        = APIEndpoint{"GET", "arvados/v1/users", ""}
+       EndpointUserMerge                       = APIEndpoint{"POST", "arvados/v1/users/merge", ""}
+       EndpointUserSetup                       = APIEndpoint{"POST", "arvados/v1/users/setup", "user"}
+       EndpointUserSystem                      = APIEndpoint{"GET", "arvados/v1/users/system", ""}
+       EndpointUserUnsetup                     = APIEndpoint{"POST", "arvados/v1/users/{uuid}/unsetup", ""}
+       EndpointUserUpdate                      = APIEndpoint{"PATCH", "arvados/v1/users/{uuid}", "user"}
+       EndpointUserBatchUpdate                 = APIEndpoint{"PATCH", "arvados/v1/users/batch_update", ""}
+       EndpointUserAuthenticate                = APIEndpoint{"POST", "arvados/v1/users/authenticate", ""}
+       EndpointAPIClientAuthorizationCurrent   = APIEndpoint{"GET", "arvados/v1/api_client_authorizations/current", ""}
+       EndpointAPIClientAuthorizationCreate    = APIEndpoint{"POST", "arvados/v1/api_client_authorizations", "api_client_authorization"}
+       EndpointAPIClientAuthorizationUpdate    = APIEndpoint{"PUT", "arvados/v1/api_client_authorizations/{uuid}", "api_client_authorization"}
+       EndpointAPIClientAuthorizationList      = APIEndpoint{"GET", "arvados/v1/api_client_authorizations", ""}
+       EndpointAPIClientAuthorizationDelete    = APIEndpoint{"DELETE", "arvados/v1/api_client_authorizations/{uuid}", ""}
+       EndpointAPIClientAuthorizationGet       = APIEndpoint{"GET", "arvados/v1/api_client_authorizations/{uuid}", ""}
 )
 
 type ContainerSSHOptions struct {
@@ -310,6 +311,7 @@ type API interface {
        ContainerRequestGet(ctx context.Context, options GetOptions) (ContainerRequest, error)
        ContainerRequestList(ctx context.Context, options ListOptions) (ContainerRequestList, error)
        ContainerRequestDelete(ctx context.Context, options DeleteOptions) (ContainerRequest, error)
+       ContainerRequestContainerStatus(ctx context.Context, options GetOptions) (ContainerStatus, error)
        ContainerRequestLog(ctx context.Context, options ContainerLogOptions) (http.Handler, error)
        GroupCreate(ctx context.Context, options CreateOptions) (Group, error)
        GroupUpdate(ctx context.Context, options UpdateOptions) (Group, error)
index 2467e807a1253e2764ae657bb0ce78ee10399ee1..91c8fbfe2936d972b8c5f196467072a9d7715b84 100644 (file)
@@ -160,3 +160,9 @@ const (
        ContainerRequestStateCommitted  = ContainerRequestState("Committed")
        ContainerRequestStateFinal      = ContainerRequestState("Final")
 )
+
+type ContainerStatus struct {
+       UUID             string         `json:"uuid"`
+       State            ContainerState `json:"container_state"`
+       SchedulingStatus string         `json:"scheduling_status"`
+}
index 3ba794380f6f9ffd4fc755fdd732c82a3a2725fd..e1827b5d1f7995e3c3e01baa52ef016f349dcd95 100644 (file)
@@ -168,6 +168,10 @@ func (as *APIStub) ContainerRequestDelete(ctx context.Context, options arvados.D
        as.appendCall(ctx, as.ContainerRequestDelete, options)
        return arvados.ContainerRequest{}, as.Error
 }
+func (as *APIStub) ContainerRequestContainerStatus(ctx context.Context, options arvados.GetOptions) (arvados.ContainerStatus, error) {
+       as.appendCall(ctx, as.ContainerRequestContainerStatus, options)
+       return arvados.ContainerStatus{}, as.Error
+}
 func (as *APIStub) ContainerRequestLog(ctx context.Context, options arvados.ContainerLogOptions) (http.Handler, error) {
        as.appendCall(ctx, as.ContainerRequestLog, options)
        // Return a handler that responds with the configured
index 87e2737575675e2d37fc9c2b778771be89001193..b87e86f664de7e3230331e8233744ac589e4a169 100644 (file)
@@ -44,7 +44,9 @@ Rails.application.routes.draw do
         get 'secret_mounts', on: :member
         get 'current', on: :collection
       end
-      resources :container_requests
+      resources :container_requests do
+        get 'container_status', on: :member
+      end
       resources :jobs do
         get 'queue', on: :collection
         get 'queue_size', on: :collection