1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
15 "git.arvados.org/arvados.git/sdk/go/auth"
16 "git.arvados.org/arvados.git/sdk/go/httpserver"
19 func remoteContainerRequestCreate(
20 h *genericFederatedRequestHandler,
21 effectiveMethod string,
25 w http.ResponseWriter,
26 req *http.Request) bool {
28 if effectiveMethod != "POST" || uuid != "" || remainder != "" {
32 // First make sure supplied token is valid.
33 creds := auth.NewCredentials()
34 creds.LoadTokensFromHTTPRequest(req)
36 currentUser, ok, err := h.handler.validateAPItoken(req, creds.Tokens[0])
38 httpserver.Error(w, err.Error(), http.StatusInternalServerError)
41 httpserver.Error(w, "invalid API token", http.StatusForbidden)
45 if *clusterID == "" || *clusterID == h.handler.Cluster.ClusterID {
46 // Submitting container request to local cluster. No
47 // need to set a runtime_token (rails api will create
48 // one when the container runs) or do a remote cluster
53 if req.Header.Get("Content-Type") != "application/json" {
54 httpserver.Error(w, "Expected Content-Type: application/json, got "+req.Header.Get("Content-Type"), http.StatusBadRequest)
58 originalBody := req.Body
59 defer originalBody.Close()
60 var request map[string]interface{}
61 err = json.NewDecoder(req.Body).Decode(&request)
63 httpserver.Error(w, err.Error(), http.StatusBadRequest)
67 crString, ok := request["container_request"].(string)
69 var crJSON map[string]interface{}
70 err := json.Unmarshal([]byte(crString), &crJSON)
72 httpserver.Error(w, err.Error(), http.StatusBadRequest)
76 request["container_request"] = crJSON
79 containerRequest, ok := request["container_request"].(map[string]interface{})
81 // Use toplevel object as the container_request object
82 containerRequest = request
85 // If runtime_token is not set, create a new token
86 if _, ok := containerRequest["runtime_token"]; !ok {
87 if len(currentUser.Authorization.Scopes) != 1 || currentUser.Authorization.Scopes[0] != "all" {
88 httpserver.Error(w, "Token scope is not [all]", http.StatusForbidden)
92 if strings.HasPrefix(currentUser.Authorization.UUID, h.handler.Cluster.ClusterID) {
93 // Local user, submitting to a remote cluster.
94 // Create a new time-limited token.
95 newtok, err := h.handler.createAPItoken(req, currentUser.UUID, nil)
97 httpserver.Error(w, err.Error(), http.StatusForbidden)
100 containerRequest["runtime_token"] = newtok.TokenV2()
102 // Remote user. Container request will use the
103 // current token, minus the trailing portion
104 // (optional container uuid).
105 sp := strings.Split(creds.Tokens[0], "/")
107 containerRequest["runtime_token"] = strings.Join(sp[0:3], "/")
109 containerRequest["runtime_token"] = creds.Tokens[0]
114 newbody, err := json.Marshal(request)
115 buf := bytes.NewBuffer(newbody)
116 req.Body = ioutil.NopCloser(buf)
117 req.ContentLength = int64(buf.Len())
118 req.Header.Set("Content-Length", fmt.Sprintf("%v", buf.Len()))
120 resp, err := h.handler.remoteClusterRequest(*clusterID, req)
121 h.handler.proxy.ForwardResponse(w, resp, err)