From 60b6f4e619f1a22405e831eda2186d61f7f1ea48 Mon Sep 17 00:00:00 2001 From: Tom Clegg Date: Mon, 4 Mar 2024 19:02:44 -0500 Subject: [PATCH] 21123: Add container_requests/{uuid}/container_status endpoint. Arvados-DCO-1.1-Signed-off-by: Tom Clegg --- .../container_requests.html.textile.liquid | 20 +++ lib/controller/federation/conn.go | 4 + lib/controller/localdb/container_request.go | 91 ++++++++++ lib/controller/router/router.go | 7 + lib/controller/rpc/conn.go | 7 + sdk/go/arvados/api.go | 170 +++++++++--------- sdk/go/arvados/container.go | 6 + sdk/go/arvadostest/api.go | 4 + services/api/config/routes.rb | 4 +- 9 files changed, 228 insertions(+), 85 deletions(-) diff --git a/doc/api/methods/container_requests.html.textile.liquid b/doc/api/methods/container_requests.html.textile.liquid index c108c32808..770b56b697 100644 --- a/doc/api/methods/container_requests.html.textile.liquid +++ b/doc/api/methods/container_requests.html.textile.liquid @@ -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. diff --git a/lib/controller/federation/conn.go b/lib/controller/federation/conn.go index c5facdc7d9..949cc56dd2 100644 --- a/lib/controller/federation/conn.go +++ b/lib/controller/federation/conn.go @@ -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) } diff --git a/lib/controller/localdb/container_request.go b/lib/controller/localdb/container_request.go index 49e21840ea..0234ee8fa6 100644 --- a/lib/controller/localdb/container_request.go +++ b/lib/controller/localdb/container_request.go @@ -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 +} diff --git a/lib/controller/router/router.go b/lib/controller/router/router.go index d39f493a95..054bcffaf7 100644 --- a/lib/controller/router/router.go +++ b/lib/controller/router/router.go @@ -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{} }, diff --git a/lib/controller/rpc/conn.go b/lib/controller/rpc/conn.go index 9f518d9c7a..c6be679a25 100644 --- a/lib/controller/rpc/conn.go +++ b/lib/controller/rpc/conn.go @@ -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, diff --git a/sdk/go/arvados/api.go b/sdk/go/arvados/api.go index e7310818f7..c3d0ea8aef 100644 --- a/sdk/go/arvados/api.go +++ b/sdk/go/arvados/api.go @@ -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) diff --git a/sdk/go/arvados/container.go b/sdk/go/arvados/container.go index 2467e807a1..91c8fbfe29 100644 --- a/sdk/go/arvados/container.go +++ b/sdk/go/arvados/container.go @@ -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"` +} diff --git a/sdk/go/arvadostest/api.go b/sdk/go/arvadostest/api.go index 3ba794380f..e1827b5d1f 100644 --- a/sdk/go/arvadostest/api.go +++ b/sdk/go/arvadostest/api.go @@ -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 diff --git a/services/api/config/routes.rb b/services/api/config/routes.rb index 87e2737575..b87e86f664 100644 --- a/services/api/config/routes.rb +++ b/services/api/config/routes.rb @@ -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 -- 2.30.2