1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
19 "git.curoverse.com/arvados.git/sdk/go/arvados"
22 type contextKey string
24 const ContextKeyCredentials contextKey = "credentials"
26 type TokenProvider func(context.Context) ([]string, error)
30 httpClient http.Client
32 tokenProvider TokenProvider
35 func NewConn(clusterID string, url *url.URL, insecure bool, tp TokenProvider) *Conn {
36 transport := http.DefaultTransport
38 // It's not safe to copy *http.DefaultTransport
39 // because it has a mutex (which might be locked)
40 // protecting a private map (which might not be nil).
41 // So we build our own, using the Go 1.12 default
42 // values, ignoring any changes the application has
43 // made to http.DefaultTransport.
44 transport = &http.Transport{
45 DialContext: (&net.Dialer{
46 Timeout: 30 * time.Second,
47 KeepAlive: 30 * time.Second,
51 IdleConnTimeout: 90 * time.Second,
52 TLSHandshakeTimeout: 10 * time.Second,
53 ExpectContinueTimeout: 1 * time.Second,
54 TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
59 httpClient: http.Client{Transport: transport},
65 func (conn *Conn) requestAndDecode(ctx context.Context, dst interface{}, ep arvados.APIEndpoint, body io.Reader, opts interface{}) error {
66 aClient := arvados.Client{
67 Client: &conn.httpClient,
68 Scheme: conn.baseURL.Scheme,
69 APIHost: conn.baseURL.Host,
71 tokens, err := conn.tokenProvider(ctx)
74 } else if len(tokens) > 0 {
75 ctx = context.WithValue(ctx, "Authorization", "Bearer "+tokens[0])
77 // Use a non-empty auth string to ensure we override
78 // any default token set on aClient -- and to avoid
79 // having the remote prompt us to send a token by
81 ctx = context.WithValue(ctx, "Authorization", "Bearer -")
84 // Encode opts to JSON and decode from there to a
85 // map[string]interface{}, so we can munge the query params
86 // using the JSON key names specified by opts' struct tags.
87 j, err := json.Marshal(opts)
89 return fmt.Errorf("%T: requestAndDecode: Marshal opts: %s", conn, err)
91 var params map[string]interface{}
92 err = json.Unmarshal(j, ¶ms)
94 return fmt.Errorf("%T: requestAndDecode: Unmarshal opts: %s", conn, err)
96 if attrs, ok := params["attrs"]; ok && ep.AttrsKey != "" {
97 params[ep.AttrsKey] = attrs
98 delete(params, "attrs")
100 if limit, ok := params["limit"].(float64); ok && limit < 0 {
101 // Negative limit means "not specified" here, but some
102 // servers/versions do not accept that, so we need to
103 // remove it entirely.
104 delete(params, "limit")
107 params["reader_tokens"] = tokens[1:]
110 if strings.Contains(ep.Path, "/:uuid") {
111 uuid, _ := params["uuid"].(string)
112 path = strings.Replace(path, "/:uuid", "/"+uuid, 1)
113 delete(params, "uuid")
115 return aClient.RequestAndDecodeContext(ctx, dst, ep.Method, path, body, params)
118 func (conn *Conn) CollectionCreate(ctx context.Context, options arvados.CreateOptions) (arvados.Collection, error) {
119 ep := arvados.EndpointCollectionCreate
120 var resp arvados.Collection
121 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
125 func (conn *Conn) CollectionUpdate(ctx context.Context, options arvados.UpdateOptions) (arvados.Collection, error) {
126 ep := arvados.EndpointCollectionUpdate
127 var resp arvados.Collection
128 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
132 func (conn *Conn) CollectionGet(ctx context.Context, options arvados.GetOptions) (arvados.Collection, error) {
133 ep := arvados.EndpointCollectionGet
134 var resp arvados.Collection
135 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
139 func (conn *Conn) CollectionList(ctx context.Context, options arvados.ListOptions) (arvados.CollectionList, error) {
140 ep := arvados.EndpointCollectionList
141 var resp arvados.CollectionList
142 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
146 func (conn *Conn) CollectionProvenance(ctx context.Context, options arvados.GetOptions) (map[string]interface{}, error) {
147 ep := arvados.EndpointCollectionProvenance
148 var resp map[string]interface{}
149 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
153 func (conn *Conn) CollectionUsedBy(ctx context.Context, options arvados.GetOptions) (map[string]interface{}, error) {
154 ep := arvados.EndpointCollectionUsedBy
155 var resp map[string]interface{}
156 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
160 func (conn *Conn) CollectionDelete(ctx context.Context, options arvados.DeleteOptions) (arvados.Collection, error) {
161 ep := arvados.EndpointCollectionDelete
162 var resp arvados.Collection
163 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
167 func (conn *Conn) ContainerCreate(ctx context.Context, options arvados.CreateOptions) (arvados.Container, error) {
168 ep := arvados.EndpointContainerCreate
169 var resp arvados.Container
170 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
174 func (conn *Conn) ContainerUpdate(ctx context.Context, options arvados.UpdateOptions) (arvados.Container, error) {
175 ep := arvados.EndpointContainerUpdate
176 var resp arvados.Container
177 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
181 func (conn *Conn) ContainerGet(ctx context.Context, options arvados.GetOptions) (arvados.Container, error) {
182 ep := arvados.EndpointContainerGet
183 var resp arvados.Container
184 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
188 func (conn *Conn) ContainerList(ctx context.Context, options arvados.ListOptions) (arvados.ContainerList, error) {
189 ep := arvados.EndpointContainerList
190 var resp arvados.ContainerList
191 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
195 func (conn *Conn) ContainerDelete(ctx context.Context, options arvados.DeleteOptions) (arvados.Container, error) {
196 ep := arvados.EndpointContainerDelete
197 var resp arvados.Container
198 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
202 func (conn *Conn) ContainerLock(ctx context.Context, options arvados.GetOptions) (arvados.Container, error) {
203 ep := arvados.EndpointContainerLock
204 var resp arvados.Container
205 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
209 func (conn *Conn) ContainerUnlock(ctx context.Context, options arvados.GetOptions) (arvados.Container, error) {
210 ep := arvados.EndpointContainerUnlock
211 var resp arvados.Container
212 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
216 func (conn *Conn) SpecimenCreate(ctx context.Context, options arvados.CreateOptions) (arvados.Specimen, error) {
217 ep := arvados.EndpointSpecimenCreate
218 var resp arvados.Specimen
219 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
223 func (conn *Conn) SpecimenUpdate(ctx context.Context, options arvados.UpdateOptions) (arvados.Specimen, error) {
224 ep := arvados.EndpointSpecimenUpdate
225 var resp arvados.Specimen
226 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
230 func (conn *Conn) SpecimenGet(ctx context.Context, options arvados.GetOptions) (arvados.Specimen, error) {
231 ep := arvados.EndpointSpecimenGet
232 var resp arvados.Specimen
233 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
237 func (conn *Conn) SpecimenList(ctx context.Context, options arvados.ListOptions) (arvados.SpecimenList, error) {
238 ep := arvados.EndpointSpecimenList
239 var resp arvados.SpecimenList
240 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
244 func (conn *Conn) SpecimenDelete(ctx context.Context, options arvados.DeleteOptions) (arvados.Specimen, error) {
245 ep := arvados.EndpointSpecimenDelete
246 var resp arvados.Specimen
247 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
251 func (conn *Conn) APIClientAuthorizationCurrent(ctx context.Context, options arvados.GetOptions) (arvados.APIClientAuthorization, error) {
252 ep := arvados.EndpointAPIClientAuthorizationCurrent
253 var resp arvados.APIClientAuthorization
254 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)