1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
24 "git.arvados.org/arvados.git/sdk/go/arvados"
25 "git.arvados.org/arvados.git/sdk/go/auth"
26 "git.arvados.org/arvados.git/sdk/go/ctxlog"
27 "git.arvados.org/arvados.git/sdk/go/httpserver"
30 const rfc3339NanoFixed = "2006-01-02T15:04:05.000000000Z07:00"
32 type TokenProvider func(context.Context) ([]string, error)
34 func PassthroughTokenProvider(ctx context.Context) ([]string, error) {
35 incoming, ok := auth.FromContext(ctx)
37 return nil, errors.New("no token provided")
39 return incoming.Tokens, nil
43 SendHeader http.Header
44 RedactHostInErrors bool
47 httpClient http.Client
49 tokenProvider TokenProvider
52 func NewConn(clusterID string, url *url.URL, insecure bool, tp TokenProvider) *Conn {
53 transport := http.DefaultTransport
55 // It's not safe to copy *http.DefaultTransport
56 // because it has a mutex (which might be locked)
57 // protecting a private map (which might not be nil).
58 // So we build our own, using the Go 1.12 default
59 // values, ignoring any changes the application has
60 // made to http.DefaultTransport.
61 transport = &http.Transport{
62 DialContext: (&net.Dialer{
63 Timeout: 30 * time.Second,
64 KeepAlive: 30 * time.Second,
68 IdleConnTimeout: 90 * time.Second,
69 TLSHandshakeTimeout: 10 * time.Second,
70 ExpectContinueTimeout: 1 * time.Second,
71 TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
76 httpClient: http.Client{
77 CheckRedirect: func(req *http.Request, via []*http.Request) error { return http.ErrUseLastResponse },
85 func (conn *Conn) requestAndDecode(ctx context.Context, dst interface{}, ep arvados.APIEndpoint, body io.Reader, opts interface{}) error {
86 aClient := arvados.Client{
87 Client: &conn.httpClient,
88 Scheme: conn.baseURL.Scheme,
89 APIHost: conn.baseURL.Host,
90 SendHeader: conn.SendHeader,
92 tokens, err := conn.tokenProvider(ctx)
95 } else if len(tokens) > 0 {
96 ctx = arvados.ContextWithAuthorization(ctx, "Bearer "+tokens[0])
98 // Use a non-empty auth string to ensure we override
99 // any default token set on aClient -- and to avoid
100 // having the remote prompt us to send a token by
102 ctx = arvados.ContextWithAuthorization(ctx, "Bearer -")
105 // Encode opts to JSON and decode from there to a
106 // map[string]interface{}, so we can munge the query params
107 // using the JSON key names specified by opts' struct tags.
108 j, err := json.Marshal(opts)
110 return fmt.Errorf("%T: requestAndDecode: Marshal opts: %s", conn, err)
112 var params map[string]interface{}
113 dec := json.NewDecoder(bytes.NewBuffer(j))
115 err = dec.Decode(¶ms)
117 return fmt.Errorf("%T: requestAndDecode: Decode opts: %s", conn, err)
119 if attrs, ok := params["attrs"]; ok && ep.AttrsKey != "" {
120 params[ep.AttrsKey] = attrs
121 delete(params, "attrs")
123 if limitStr, ok := params["limit"]; ok {
124 if limit, err := strconv.ParseInt(string(limitStr.(json.Number)), 10, 64); err == nil && limit < 0 {
125 // Negative limit means "not specified" here, but some
126 // servers/versions do not accept that, so we need to
127 // remove it entirely.
128 delete(params, "limit")
132 if authinfo, ok := params["auth_info"]; ok {
133 if tmp, ok2 := authinfo.(map[string]interface{}); ok2 {
134 for k, v := range tmp {
135 if strings.HasSuffix(k, "_at") {
136 // Change zero times values to nil
137 if v, ok3 := v.(string); ok3 && (strings.HasPrefix(v, "0001-01-01T00:00:00") || v == "") {
146 params["reader_tokens"] = tokens[1:]
149 if strings.Contains(ep.Path, "/{uuid}") {
150 uuid, _ := params["uuid"].(string)
151 path = strings.Replace(path, "/{uuid}", "/"+uuid, 1)
152 delete(params, "uuid")
154 err = aClient.RequestAndDecodeContext(ctx, dst, ep.Method, path, body, params)
155 if err != nil && conn.RedactHostInErrors {
156 redacted := strings.Replace(err.Error(), strings.TrimSuffix(conn.baseURL.String(), "/"), "//railsapi.internal", -1)
157 if strings.HasPrefix(redacted, "request failed: ") {
158 redacted = strings.Replace(redacted, "request failed: ", "", -1)
160 if redacted != err.Error() {
161 if err, ok := err.(httpStatusError); ok {
162 return wrapHTTPStatusError(err, redacted)
164 return errors.New(redacted)
171 func (conn *Conn) BaseURL() url.URL {
175 func (conn *Conn) ConfigGet(ctx context.Context) (json.RawMessage, error) {
176 ep := arvados.EndpointConfigGet
177 var resp json.RawMessage
178 err := conn.requestAndDecode(ctx, &resp, ep, nil, nil)
182 func (conn *Conn) VocabularyGet(ctx context.Context) (arvados.Vocabulary, error) {
183 ep := arvados.EndpointVocabularyGet
184 var resp arvados.Vocabulary
185 err := conn.requestAndDecode(ctx, &resp, ep, nil, nil)
189 func (conn *Conn) Login(ctx context.Context, options arvados.LoginOptions) (arvados.LoginResponse, error) {
190 ep := arvados.EndpointLogin
191 var resp arvados.LoginResponse
192 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
193 resp.RedirectLocation = conn.relativeToBaseURL(resp.RedirectLocation)
197 func (conn *Conn) Logout(ctx context.Context, options arvados.LogoutOptions) (arvados.LogoutResponse, error) {
198 ep := arvados.EndpointLogout
199 var resp arvados.LogoutResponse
200 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
201 resp.RedirectLocation = conn.relativeToBaseURL(resp.RedirectLocation)
205 // If the given location is a valid URL and its origin is the same as
206 // conn.baseURL, return it as a relative URL. Otherwise, return it
208 func (conn *Conn) relativeToBaseURL(location string) string {
209 u, err := url.Parse(location)
210 if err == nil && u.Scheme == conn.baseURL.Scheme && strings.ToLower(u.Host) == strings.ToLower(conn.baseURL.Host) {
220 func (conn *Conn) CollectionCreate(ctx context.Context, options arvados.CreateOptions) (arvados.Collection, error) {
221 ep := arvados.EndpointCollectionCreate
222 var resp arvados.Collection
223 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
227 func (conn *Conn) CollectionUpdate(ctx context.Context, options arvados.UpdateOptions) (arvados.Collection, error) {
228 ep := arvados.EndpointCollectionUpdate
229 var resp arvados.Collection
230 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
234 func (conn *Conn) CollectionGet(ctx context.Context, options arvados.GetOptions) (arvados.Collection, error) {
235 ep := arvados.EndpointCollectionGet
236 var resp arvados.Collection
237 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
241 func (conn *Conn) CollectionList(ctx context.Context, options arvados.ListOptions) (arvados.CollectionList, error) {
242 ep := arvados.EndpointCollectionList
243 var resp arvados.CollectionList
244 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
248 func (conn *Conn) CollectionProvenance(ctx context.Context, options arvados.GetOptions) (map[string]interface{}, error) {
249 ep := arvados.EndpointCollectionProvenance
250 var resp map[string]interface{}
251 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
255 func (conn *Conn) CollectionUsedBy(ctx context.Context, options arvados.GetOptions) (map[string]interface{}, error) {
256 ep := arvados.EndpointCollectionUsedBy
257 var resp map[string]interface{}
258 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
262 func (conn *Conn) CollectionDelete(ctx context.Context, options arvados.DeleteOptions) (arvados.Collection, error) {
263 ep := arvados.EndpointCollectionDelete
264 var resp arvados.Collection
265 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
269 func (conn *Conn) CollectionTrash(ctx context.Context, options arvados.DeleteOptions) (arvados.Collection, error) {
270 ep := arvados.EndpointCollectionTrash
271 var resp arvados.Collection
272 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
276 func (conn *Conn) CollectionUntrash(ctx context.Context, options arvados.UntrashOptions) (arvados.Collection, error) {
277 ep := arvados.EndpointCollectionUntrash
278 var resp arvados.Collection
279 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
283 func (conn *Conn) ContainerCreate(ctx context.Context, options arvados.CreateOptions) (arvados.Container, error) {
284 ep := arvados.EndpointContainerCreate
285 var resp arvados.Container
286 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
290 func (conn *Conn) ContainerUpdate(ctx context.Context, options arvados.UpdateOptions) (arvados.Container, error) {
291 ep := arvados.EndpointContainerUpdate
292 var resp arvados.Container
293 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
297 func (conn *Conn) ContainerGet(ctx context.Context, options arvados.GetOptions) (arvados.Container, error) {
298 ep := arvados.EndpointContainerGet
299 var resp arvados.Container
300 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
304 func (conn *Conn) ContainerList(ctx context.Context, options arvados.ListOptions) (arvados.ContainerList, error) {
305 ep := arvados.EndpointContainerList
306 var resp arvados.ContainerList
307 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
311 func (conn *Conn) ContainerDelete(ctx context.Context, options arvados.DeleteOptions) (arvados.Container, error) {
312 ep := arvados.EndpointContainerDelete
313 var resp arvados.Container
314 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
318 func (conn *Conn) ContainerLock(ctx context.Context, options arvados.GetOptions) (arvados.Container, error) {
319 ep := arvados.EndpointContainerLock
320 var resp arvados.Container
321 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
325 func (conn *Conn) ContainerUnlock(ctx context.Context, options arvados.GetOptions) (arvados.Container, error) {
326 ep := arvados.EndpointContainerUnlock
327 var resp arvados.Container
328 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
332 // ContainerSSH returns a connection to the out-of-band SSH server for
333 // a running container. If the returned error is nil, the caller is
334 // responsible for closing sshconn.Conn.
335 func (conn *Conn) ContainerSSH(ctx context.Context, options arvados.ContainerSSHOptions) (sshconn arvados.ConnectionResponse, err error) {
336 u, err := conn.baseURL.Parse("/" + strings.Replace(arvados.EndpointContainerSSH.Path, "{uuid}", options.UUID, -1))
338 err = fmt.Errorf("url.Parse: %w", err)
341 return conn.socket(ctx, u, "ssh", url.Values{
342 "detach_keys": {options.DetachKeys},
343 "login_username": {options.LoginUsername},
344 "no_forward": {fmt.Sprintf("%v", options.NoForward)},
348 // ContainerGatewayTunnel returns a connection to a yamux session on
349 // the controller. The caller should connect the returned resp.Conn to
350 // a client-side yamux session.
351 func (conn *Conn) ContainerGatewayTunnel(ctx context.Context, options arvados.ContainerGatewayTunnelOptions) (tunnelconn arvados.ConnectionResponse, err error) {
352 u, err := conn.baseURL.Parse("/" + strings.Replace(arvados.EndpointContainerGatewayTunnel.Path, "{uuid}", options.UUID, -1))
354 err = fmt.Errorf("url.Parse: %w", err)
357 return conn.socket(ctx, u, "tunnel", url.Values{
358 "auth_secret": {options.AuthSecret},
362 // socket sets up a socket using the specified API endpoint and
364 func (conn *Conn) socket(ctx context.Context, u *url.URL, upgradeHeader string, postform url.Values) (connresp arvados.ConnectionResponse, err error) {
365 addr := conn.baseURL.Host
366 if strings.Index(addr, ":") < 1 || (strings.Contains(addr, "::") && addr[0] != '[') {
367 // hostname or ::1 or 1::1
368 addr = net.JoinHostPort(addr, "https")
371 if tlsconf := conn.httpClient.Transport.(*http.Transport).TLSClientConfig; tlsconf != nil && tlsconf.InsecureSkipVerify {
374 netconn, err := tls.Dial("tcp", addr, &tls.Config{InsecureSkipVerify: insecure})
376 return connresp, fmt.Errorf("tls.Dial: %w", err)
383 bufr := bufio.NewReader(netconn)
384 bufw := bufio.NewWriter(netconn)
386 tokens, err := conn.tokenProvider(ctx)
389 } else if len(tokens) < 1 {
390 return connresp, httpserver.ErrorWithStatus(errors.New("unauthorized"), http.StatusUnauthorized)
392 postdata := postform.Encode()
393 bufw.WriteString("POST " + u.String() + " HTTP/1.1\r\n")
394 bufw.WriteString("Authorization: Bearer " + tokens[0] + "\r\n")
395 bufw.WriteString("Host: " + u.Host + "\r\n")
396 bufw.WriteString("Upgrade: " + upgradeHeader + "\r\n")
397 bufw.WriteString("Content-Type: application/x-www-form-urlencoded\r\n")
398 fmt.Fprintf(bufw, "Content-Length: %d\r\n", len(postdata))
399 bufw.WriteString("\r\n")
400 bufw.WriteString(postdata)
402 resp, err := http.ReadResponse(bufr, &http.Request{Method: "POST"})
404 return connresp, fmt.Errorf("http.ReadResponse: %w", err)
406 defer resp.Body.Close()
407 if resp.StatusCode != http.StatusSwitchingProtocols {
408 ctxlog.FromContext(ctx).Infof("rpc.Conn.socket: server %s did not switch protocols, got status %s", u.String(), resp.Status)
409 body, _ := ioutil.ReadAll(io.LimitReader(resp.Body, 10000))
411 var errDoc httpserver.ErrorResponse
412 if err := json.Unmarshal(body, &errDoc); err == nil {
413 message = strings.Join(errDoc.Errors, "; ")
415 message = fmt.Sprintf("%q", body)
417 return connresp, fmt.Errorf("server did not provide a tunnel: %s: %s", resp.Status, message)
419 if strings.ToLower(resp.Header.Get("Upgrade")) != upgradeHeader ||
420 strings.ToLower(resp.Header.Get("Connection")) != "upgrade" {
421 return connresp, fmt.Errorf("bad response from server: Upgrade %q Connection %q", resp.Header.Get("Upgrade"), resp.Header.Get("Connection"))
423 connresp.Conn = netconn
424 connresp.Bufrw = &bufio.ReadWriter{Reader: bufr, Writer: bufw}
425 connresp.Header = resp.Header
429 func (conn *Conn) ContainerRequestCreate(ctx context.Context, options arvados.CreateOptions) (arvados.ContainerRequest, error) {
430 ep := arvados.EndpointContainerRequestCreate
431 var resp arvados.ContainerRequest
432 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
436 func (conn *Conn) ContainerRequestUpdate(ctx context.Context, options arvados.UpdateOptions) (arvados.ContainerRequest, error) {
437 ep := arvados.EndpointContainerRequestUpdate
438 var resp arvados.ContainerRequest
439 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
443 func (conn *Conn) ContainerRequestGet(ctx context.Context, options arvados.GetOptions) (arvados.ContainerRequest, error) {
444 ep := arvados.EndpointContainerRequestGet
445 var resp arvados.ContainerRequest
446 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
450 func (conn *Conn) ContainerRequestList(ctx context.Context, options arvados.ListOptions) (arvados.ContainerRequestList, error) {
451 ep := arvados.EndpointContainerRequestList
452 var resp arvados.ContainerRequestList
453 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
457 func (conn *Conn) ContainerRequestDelete(ctx context.Context, options arvados.DeleteOptions) (arvados.ContainerRequest, error) {
458 ep := arvados.EndpointContainerRequestDelete
459 var resp arvados.ContainerRequest
460 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
464 func (conn *Conn) GroupCreate(ctx context.Context, options arvados.CreateOptions) (arvados.Group, error) {
465 ep := arvados.EndpointGroupCreate
466 var resp arvados.Group
467 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
471 func (conn *Conn) GroupUpdate(ctx context.Context, options arvados.UpdateOptions) (arvados.Group, error) {
472 ep := arvados.EndpointGroupUpdate
473 var resp arvados.Group
474 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
478 func (conn *Conn) GroupGet(ctx context.Context, options arvados.GetOptions) (arvados.Group, error) {
479 ep := arvados.EndpointGroupGet
480 var resp arvados.Group
481 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
485 func (conn *Conn) GroupList(ctx context.Context, options arvados.ListOptions) (arvados.GroupList, error) {
486 ep := arvados.EndpointGroupList
487 var resp arvados.GroupList
488 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
492 func (conn *Conn) GroupContents(ctx context.Context, options arvados.GroupContentsOptions) (arvados.ObjectList, error) {
493 ep := arvados.EndpointGroupContents
494 var resp arvados.ObjectList
495 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
499 func (conn *Conn) GroupShared(ctx context.Context, options arvados.ListOptions) (arvados.GroupList, error) {
500 ep := arvados.EndpointGroupShared
501 var resp arvados.GroupList
502 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
506 func (conn *Conn) GroupDelete(ctx context.Context, options arvados.DeleteOptions) (arvados.Group, error) {
507 ep := arvados.EndpointGroupDelete
508 var resp arvados.Group
509 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
513 func (conn *Conn) GroupTrash(ctx context.Context, options arvados.DeleteOptions) (arvados.Group, error) {
514 ep := arvados.EndpointGroupTrash
515 var resp arvados.Group
516 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
520 func (conn *Conn) GroupUntrash(ctx context.Context, options arvados.UntrashOptions) (arvados.Group, error) {
521 ep := arvados.EndpointGroupUntrash
522 var resp arvados.Group
523 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
527 func (conn *Conn) LinkCreate(ctx context.Context, options arvados.CreateOptions) (arvados.Link, error) {
528 ep := arvados.EndpointLinkCreate
529 var resp arvados.Link
530 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
534 func (conn *Conn) LinkUpdate(ctx context.Context, options arvados.UpdateOptions) (arvados.Link, error) {
535 ep := arvados.EndpointLinkUpdate
536 var resp arvados.Link
537 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
541 func (conn *Conn) LinkGet(ctx context.Context, options arvados.GetOptions) (arvados.Link, error) {
542 ep := arvados.EndpointLinkGet
543 var resp arvados.Link
544 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
548 func (conn *Conn) LinkList(ctx context.Context, options arvados.ListOptions) (arvados.LinkList, error) {
549 ep := arvados.EndpointLinkList
550 var resp arvados.LinkList
551 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
555 func (conn *Conn) LinkDelete(ctx context.Context, options arvados.DeleteOptions) (arvados.Link, error) {
556 ep := arvados.EndpointLinkDelete
557 var resp arvados.Link
558 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
562 func (conn *Conn) LogCreate(ctx context.Context, options arvados.CreateOptions) (arvados.Log, error) {
563 ep := arvados.EndpointLogCreate
565 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
569 func (conn *Conn) LogUpdate(ctx context.Context, options arvados.UpdateOptions) (arvados.Log, error) {
570 ep := arvados.EndpointLogUpdate
572 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
576 func (conn *Conn) LogGet(ctx context.Context, options arvados.GetOptions) (arvados.Log, error) {
577 ep := arvados.EndpointLogGet
579 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
583 func (conn *Conn) LogList(ctx context.Context, options arvados.ListOptions) (arvados.LogList, error) {
584 ep := arvados.EndpointLogList
585 var resp arvados.LogList
586 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
590 func (conn *Conn) LogDelete(ctx context.Context, options arvados.DeleteOptions) (arvados.Log, error) {
591 ep := arvados.EndpointLogDelete
593 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
597 func (conn *Conn) SpecimenCreate(ctx context.Context, options arvados.CreateOptions) (arvados.Specimen, error) {
598 ep := arvados.EndpointSpecimenCreate
599 var resp arvados.Specimen
600 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
604 func (conn *Conn) SpecimenUpdate(ctx context.Context, options arvados.UpdateOptions) (arvados.Specimen, error) {
605 ep := arvados.EndpointSpecimenUpdate
606 var resp arvados.Specimen
607 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
611 func (conn *Conn) SpecimenGet(ctx context.Context, options arvados.GetOptions) (arvados.Specimen, error) {
612 ep := arvados.EndpointSpecimenGet
613 var resp arvados.Specimen
614 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
618 func (conn *Conn) SpecimenList(ctx context.Context, options arvados.ListOptions) (arvados.SpecimenList, error) {
619 ep := arvados.EndpointSpecimenList
620 var resp arvados.SpecimenList
621 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
625 func (conn *Conn) SpecimenDelete(ctx context.Context, options arvados.DeleteOptions) (arvados.Specimen, error) {
626 ep := arvados.EndpointSpecimenDelete
627 var resp arvados.Specimen
628 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
632 func (conn *Conn) SysTrashSweep(ctx context.Context, options struct{}) (struct{}, error) {
633 ep := arvados.EndpointSysTrashSweep
635 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
639 func (conn *Conn) UserCreate(ctx context.Context, options arvados.CreateOptions) (arvados.User, error) {
640 ep := arvados.EndpointUserCreate
641 var resp arvados.User
642 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
645 func (conn *Conn) UserUpdate(ctx context.Context, options arvados.UpdateOptions) (arvados.User, error) {
646 ep := arvados.EndpointUserUpdate
647 var resp arvados.User
648 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
651 func (conn *Conn) UserMerge(ctx context.Context, options arvados.UserMergeOptions) (arvados.User, error) {
652 ep := arvados.EndpointUserMerge
653 var resp arvados.User
654 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
657 func (conn *Conn) UserActivate(ctx context.Context, options arvados.UserActivateOptions) (arvados.User, error) {
658 ep := arvados.EndpointUserActivate
659 var resp arvados.User
660 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
663 func (conn *Conn) UserSetup(ctx context.Context, options arvados.UserSetupOptions) (map[string]interface{}, error) {
664 ep := arvados.EndpointUserSetup
665 var resp map[string]interface{}
666 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
669 func (conn *Conn) UserUnsetup(ctx context.Context, options arvados.GetOptions) (arvados.User, error) {
670 ep := arvados.EndpointUserUnsetup
671 var resp arvados.User
672 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
675 func (conn *Conn) UserGet(ctx context.Context, options arvados.GetOptions) (arvados.User, error) {
676 ep := arvados.EndpointUserGet
677 var resp arvados.User
678 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
681 func (conn *Conn) UserGetCurrent(ctx context.Context, options arvados.GetOptions) (arvados.User, error) {
682 ep := arvados.EndpointUserGetCurrent
683 var resp arvados.User
684 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
687 func (conn *Conn) UserGetSystem(ctx context.Context, options arvados.GetOptions) (arvados.User, error) {
688 ep := arvados.EndpointUserGetSystem
689 var resp arvados.User
690 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
693 func (conn *Conn) UserList(ctx context.Context, options arvados.ListOptions) (arvados.UserList, error) {
694 ep := arvados.EndpointUserList
695 var resp arvados.UserList
696 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
699 func (conn *Conn) UserDelete(ctx context.Context, options arvados.DeleteOptions) (arvados.User, error) {
700 ep := arvados.EndpointUserDelete
701 var resp arvados.User
702 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
706 func (conn *Conn) APIClientAuthorizationCurrent(ctx context.Context, options arvados.GetOptions) (arvados.APIClientAuthorization, error) {
707 ep := arvados.EndpointAPIClientAuthorizationCurrent
708 var resp arvados.APIClientAuthorization
709 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
712 func (conn *Conn) APIClientAuthorizationCreate(ctx context.Context, options arvados.CreateOptions) (arvados.APIClientAuthorization, error) {
713 ep := arvados.EndpointAPIClientAuthorizationCreate
714 var resp arvados.APIClientAuthorization
715 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
718 func (conn *Conn) APIClientAuthorizationUpdate(ctx context.Context, options arvados.UpdateOptions) (arvados.APIClientAuthorization, error) {
719 ep := arvados.EndpointAPIClientAuthorizationUpdate
720 var resp arvados.APIClientAuthorization
721 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
724 func (conn *Conn) APIClientAuthorizationDelete(ctx context.Context, options arvados.DeleteOptions) (arvados.APIClientAuthorization, error) {
725 ep := arvados.EndpointAPIClientAuthorizationDelete
726 var resp arvados.APIClientAuthorization
727 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
730 func (conn *Conn) APIClientAuthorizationList(ctx context.Context, options arvados.ListOptions) (arvados.APIClientAuthorizationList, error) {
731 ep := arvados.EndpointAPIClientAuthorizationList
732 var resp arvados.APIClientAuthorizationList
733 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
736 func (conn *Conn) APIClientAuthorizationGet(ctx context.Context, options arvados.GetOptions) (arvados.APIClientAuthorization, error) {
737 ep := arvados.EndpointAPIClientAuthorizationGet
738 var resp arvados.APIClientAuthorization
739 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
743 type UserSessionAuthInfo struct {
744 UserUUID string `json:"user_uuid"`
745 Email string `json:"email"`
746 AlternateEmails []string `json:"alternate_emails"`
747 FirstName string `json:"first_name"`
748 LastName string `json:"last_name"`
749 Username string `json:"username"`
750 ExpiresAt time.Time `json:"expires_at"`
753 type UserSessionCreateOptions struct {
754 AuthInfo UserSessionAuthInfo `json:"auth_info"`
755 ReturnTo string `json:"return_to"`
758 func (conn *Conn) UserSessionCreate(ctx context.Context, options UserSessionCreateOptions) (arvados.LoginResponse, error) {
759 ep := arvados.APIEndpoint{Method: "POST", Path: "auth/controller/callback"}
760 var resp arvados.LoginResponse
761 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
765 func (conn *Conn) UserBatchUpdate(ctx context.Context, options arvados.UserBatchUpdateOptions) (arvados.UserList, error) {
766 ep := arvados.EndpointUserBatchUpdate
767 var resp arvados.UserList
768 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
772 func (conn *Conn) UserAuthenticate(ctx context.Context, options arvados.UserAuthenticateOptions) (arvados.APIClientAuthorization, error) {
773 ep := arvados.EndpointUserAuthenticate
774 var resp arvados.APIClientAuthorization
775 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
779 // httpStatusError is an error with an HTTP status code that can be
780 // propagated by lib/controller/router, etc.
781 type httpStatusError interface {
786 // wrappedHTTPStatusError is used to augment/replace an error message
787 // while preserving the HTTP status code indicated by the original
789 type wrappedHTTPStatusError struct {
794 func wrapHTTPStatusError(err httpStatusError, message string) httpStatusError {
795 return wrappedHTTPStatusError{err, message}
798 func (err wrappedHTTPStatusError) Error() string {