1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
20 "git.curoverse.com/arvados.git/sdk/go/arvados"
21 "git.curoverse.com/arvados.git/sdk/go/auth"
24 type TokenProvider func(context.Context) ([]string, error)
26 func PassthroughTokenProvider(ctx context.Context) ([]string, error) {
27 if incoming, ok := auth.FromContext(ctx); !ok {
28 return nil, errors.New("no token provided")
30 return incoming.Tokens, nil
36 httpClient http.Client
38 tokenProvider TokenProvider
41 func NewConn(clusterID string, url *url.URL, insecure bool, tp TokenProvider) *Conn {
42 transport := http.DefaultTransport
44 // It's not safe to copy *http.DefaultTransport
45 // because it has a mutex (which might be locked)
46 // protecting a private map (which might not be nil).
47 // So we build our own, using the Go 1.12 default
48 // values, ignoring any changes the application has
49 // made to http.DefaultTransport.
50 transport = &http.Transport{
51 DialContext: (&net.Dialer{
52 Timeout: 30 * time.Second,
53 KeepAlive: 30 * time.Second,
57 IdleConnTimeout: 90 * time.Second,
58 TLSHandshakeTimeout: 10 * time.Second,
59 ExpectContinueTimeout: 1 * time.Second,
60 TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
65 httpClient: http.Client{Transport: transport},
71 func (conn *Conn) requestAndDecode(ctx context.Context, dst interface{}, ep arvados.APIEndpoint, body io.Reader, opts interface{}) error {
72 aClient := arvados.Client{
73 Client: &conn.httpClient,
74 Scheme: conn.baseURL.Scheme,
75 APIHost: conn.baseURL.Host,
77 tokens, err := conn.tokenProvider(ctx)
80 } else if len(tokens) > 0 {
81 ctx = arvados.ContextWithAuthorization(ctx, "Bearer "+tokens[0])
83 // Use a non-empty auth string to ensure we override
84 // any default token set on aClient -- and to avoid
85 // having the remote prompt us to send a token by
87 ctx = arvados.ContextWithAuthorization(ctx, "Bearer -")
90 // Encode opts to JSON and decode from there to a
91 // map[string]interface{}, so we can munge the query params
92 // using the JSON key names specified by opts' struct tags.
93 j, err := json.Marshal(opts)
95 return fmt.Errorf("%T: requestAndDecode: Marshal opts: %s", conn, err)
97 var params map[string]interface{}
98 err = json.Unmarshal(j, ¶ms)
100 return fmt.Errorf("%T: requestAndDecode: Unmarshal opts: %s", conn, err)
102 if attrs, ok := params["attrs"]; ok && ep.AttrsKey != "" {
103 params[ep.AttrsKey] = attrs
104 delete(params, "attrs")
106 if limit, ok := params["limit"].(float64); ok && limit < 0 {
107 // Negative limit means "not specified" here, but some
108 // servers/versions do not accept that, so we need to
109 // remove it entirely.
110 delete(params, "limit")
113 params["reader_tokens"] = tokens[1:]
116 if strings.Contains(ep.Path, "/:uuid") {
117 uuid, _ := params["uuid"].(string)
118 path = strings.Replace(path, "/:uuid", "/"+uuid, 1)
119 delete(params, "uuid")
121 return aClient.RequestAndDecodeContext(ctx, dst, ep.Method, path, body, params)
124 func (conn *Conn) ConfigGet(ctx context.Context) (json.RawMessage, error) {
125 ep := arvados.EndpointConfigGet
126 var resp json.RawMessage
127 err := conn.requestAndDecode(ctx, &resp, ep, nil, nil)
131 func (conn *Conn) CollectionCreate(ctx context.Context, options arvados.CreateOptions) (arvados.Collection, error) {
132 ep := arvados.EndpointCollectionCreate
133 var resp arvados.Collection
134 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
138 func (conn *Conn) CollectionUpdate(ctx context.Context, options arvados.UpdateOptions) (arvados.Collection, error) {
139 ep := arvados.EndpointCollectionUpdate
140 var resp arvados.Collection
141 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
145 func (conn *Conn) CollectionGet(ctx context.Context, options arvados.GetOptions) (arvados.Collection, error) {
146 ep := arvados.EndpointCollectionGet
147 var resp arvados.Collection
148 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
152 func (conn *Conn) CollectionList(ctx context.Context, options arvados.ListOptions) (arvados.CollectionList, error) {
153 ep := arvados.EndpointCollectionList
154 var resp arvados.CollectionList
155 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
159 func (conn *Conn) CollectionProvenance(ctx context.Context, options arvados.GetOptions) (map[string]interface{}, error) {
160 ep := arvados.EndpointCollectionProvenance
161 var resp map[string]interface{}
162 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
166 func (conn *Conn) CollectionUsedBy(ctx context.Context, options arvados.GetOptions) (map[string]interface{}, error) {
167 ep := arvados.EndpointCollectionUsedBy
168 var resp map[string]interface{}
169 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
173 func (conn *Conn) CollectionDelete(ctx context.Context, options arvados.DeleteOptions) (arvados.Collection, error) {
174 ep := arvados.EndpointCollectionDelete
175 var resp arvados.Collection
176 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
180 func (conn *Conn) CollectionTrash(ctx context.Context, options arvados.DeleteOptions) (arvados.Collection, error) {
181 ep := arvados.EndpointCollectionTrash
182 var resp arvados.Collection
183 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
187 func (conn *Conn) CollectionUntrash(ctx context.Context, options arvados.UntrashOptions) (arvados.Collection, error) {
188 ep := arvados.EndpointCollectionUntrash
189 var resp arvados.Collection
190 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
194 func (conn *Conn) ContainerCreate(ctx context.Context, options arvados.CreateOptions) (arvados.Container, error) {
195 ep := arvados.EndpointContainerCreate
196 var resp arvados.Container
197 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
201 func (conn *Conn) ContainerUpdate(ctx context.Context, options arvados.UpdateOptions) (arvados.Container, error) {
202 ep := arvados.EndpointContainerUpdate
203 var resp arvados.Container
204 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
208 func (conn *Conn) ContainerGet(ctx context.Context, options arvados.GetOptions) (arvados.Container, error) {
209 ep := arvados.EndpointContainerGet
210 var resp arvados.Container
211 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
215 func (conn *Conn) ContainerList(ctx context.Context, options arvados.ListOptions) (arvados.ContainerList, error) {
216 ep := arvados.EndpointContainerList
217 var resp arvados.ContainerList
218 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
222 func (conn *Conn) ContainerDelete(ctx context.Context, options arvados.DeleteOptions) (arvados.Container, error) {
223 ep := arvados.EndpointContainerDelete
224 var resp arvados.Container
225 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
229 func (conn *Conn) ContainerLock(ctx context.Context, options arvados.GetOptions) (arvados.Container, error) {
230 ep := arvados.EndpointContainerLock
231 var resp arvados.Container
232 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
236 func (conn *Conn) ContainerUnlock(ctx context.Context, options arvados.GetOptions) (arvados.Container, error) {
237 ep := arvados.EndpointContainerUnlock
238 var resp arvados.Container
239 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
243 func (conn *Conn) SpecimenCreate(ctx context.Context, options arvados.CreateOptions) (arvados.Specimen, error) {
244 ep := arvados.EndpointSpecimenCreate
245 var resp arvados.Specimen
246 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
250 func (conn *Conn) SpecimenUpdate(ctx context.Context, options arvados.UpdateOptions) (arvados.Specimen, error) {
251 ep := arvados.EndpointSpecimenUpdate
252 var resp arvados.Specimen
253 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
257 func (conn *Conn) SpecimenGet(ctx context.Context, options arvados.GetOptions) (arvados.Specimen, error) {
258 ep := arvados.EndpointSpecimenGet
259 var resp arvados.Specimen
260 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
264 func (conn *Conn) SpecimenList(ctx context.Context, options arvados.ListOptions) (arvados.SpecimenList, error) {
265 ep := arvados.EndpointSpecimenList
266 var resp arvados.SpecimenList
267 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
271 func (conn *Conn) SpecimenDelete(ctx context.Context, options arvados.DeleteOptions) (arvados.Specimen, error) {
272 ep := arvados.EndpointSpecimenDelete
273 var resp arvados.Specimen
274 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)
278 func (conn *Conn) APIClientAuthorizationCurrent(ctx context.Context, options arvados.GetOptions) (arvados.APIClientAuthorization, error) {
279 ep := arvados.EndpointAPIClientAuthorizationCurrent
280 var resp arvados.APIClientAuthorization
281 err := conn.requestAndDecode(ctx, &resp, ep, nil, options)