1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
11 "git.curoverse.com/arvados.git/lib/controller/federation"
12 "git.curoverse.com/arvados.git/sdk/go/arvados"
13 "git.curoverse.com/arvados.git/sdk/go/auth"
14 "git.curoverse.com/arvados.git/sdk/go/ctxlog"
15 "github.com/julienschmidt/httprouter"
19 mux *httprouter.Router
20 fed federation.Interface
23 func New(cluster *arvados.Cluster) *router {
25 mux: httprouter.New(),
26 fed: federation.New(cluster),
28 rtr.addRoutes(cluster)
32 func (rtr *router) addRoutes(cluster *arvados.Cluster) {
33 for _, route := range []struct {
34 endpoint arvados.APIEndpoint
35 defaultOpts func() interface{}
36 exec func(ctx context.Context, opts interface{}) (interface{}, error)
39 arvados.EndpointCollectionCreate,
40 func() interface{} { return &arvados.CreateOptions{} },
41 func(ctx context.Context, opts interface{}) (interface{}, error) {
42 return rtr.fed.CollectionCreate(ctx, *opts.(*arvados.CreateOptions))
46 arvados.EndpointCollectionUpdate,
47 func() interface{} { return &arvados.UpdateOptions{} },
48 func(ctx context.Context, opts interface{}) (interface{}, error) {
49 return rtr.fed.CollectionUpdate(ctx, *opts.(*arvados.UpdateOptions))
53 arvados.EndpointCollectionGet,
54 func() interface{} { return &arvados.GetOptions{} },
55 func(ctx context.Context, opts interface{}) (interface{}, error) {
56 return rtr.fed.CollectionGet(ctx, *opts.(*arvados.GetOptions))
60 arvados.EndpointCollectionList,
61 func() interface{} { return &arvados.ListOptions{Limit: -1} },
62 func(ctx context.Context, opts interface{}) (interface{}, error) {
63 return rtr.fed.CollectionList(ctx, *opts.(*arvados.ListOptions))
67 arvados.EndpointCollectionProvenance,
68 func() interface{} { return &arvados.GetOptions{} },
69 func(ctx context.Context, opts interface{}) (interface{}, error) {
70 return rtr.fed.CollectionProvenance(ctx, *opts.(*arvados.GetOptions))
74 arvados.EndpointCollectionUsedBy,
75 func() interface{} { return &arvados.GetOptions{} },
76 func(ctx context.Context, opts interface{}) (interface{}, error) {
77 return rtr.fed.CollectionUsedBy(ctx, *opts.(*arvados.GetOptions))
81 arvados.EndpointCollectionDelete,
82 func() interface{} { return &arvados.DeleteOptions{} },
83 func(ctx context.Context, opts interface{}) (interface{}, error) {
84 return rtr.fed.CollectionDelete(ctx, *opts.(*arvados.DeleteOptions))
88 arvados.EndpointContainerCreate,
89 func() interface{} { return &arvados.CreateOptions{} },
90 func(ctx context.Context, opts interface{}) (interface{}, error) {
91 return rtr.fed.ContainerCreate(ctx, *opts.(*arvados.CreateOptions))
95 arvados.EndpointContainerUpdate,
96 func() interface{} { return &arvados.UpdateOptions{} },
97 func(ctx context.Context, opts interface{}) (interface{}, error) {
98 return rtr.fed.ContainerUpdate(ctx, *opts.(*arvados.UpdateOptions))
102 arvados.EndpointContainerGet,
103 func() interface{} { return &arvados.GetOptions{} },
104 func(ctx context.Context, opts interface{}) (interface{}, error) {
105 return rtr.fed.ContainerGet(ctx, *opts.(*arvados.GetOptions))
109 arvados.EndpointContainerList,
110 func() interface{} { return &arvados.ListOptions{Limit: -1} },
111 func(ctx context.Context, opts interface{}) (interface{}, error) {
112 return rtr.fed.ContainerList(ctx, *opts.(*arvados.ListOptions))
116 arvados.EndpointContainerDelete,
117 func() interface{} { return &arvados.DeleteOptions{} },
118 func(ctx context.Context, opts interface{}) (interface{}, error) {
119 return rtr.fed.ContainerDelete(ctx, *opts.(*arvados.DeleteOptions))
123 arvados.EndpointContainerLock,
125 return &arvados.GetOptions{Select: []string{"uuid", "state", "priority", "auth_uuid", "locked_by_uuid"}}
127 func(ctx context.Context, opts interface{}) (interface{}, error) {
128 return rtr.fed.ContainerLock(ctx, *opts.(*arvados.GetOptions))
132 arvados.EndpointContainerUnlock,
134 return &arvados.GetOptions{Select: []string{"uuid", "state", "priority", "auth_uuid", "locked_by_uuid"}}
136 func(ctx context.Context, opts interface{}) (interface{}, error) {
137 return rtr.fed.ContainerUnlock(ctx, *opts.(*arvados.GetOptions))
141 arvados.EndpointSpecimenCreate,
142 func() interface{} { return &arvados.CreateOptions{} },
143 func(ctx context.Context, opts interface{}) (interface{}, error) {
144 return rtr.fed.SpecimenCreate(ctx, *opts.(*arvados.CreateOptions))
148 arvados.EndpointSpecimenUpdate,
149 func() interface{} { return &arvados.UpdateOptions{} },
150 func(ctx context.Context, opts interface{}) (interface{}, error) {
151 return rtr.fed.SpecimenUpdate(ctx, *opts.(*arvados.UpdateOptions))
155 arvados.EndpointSpecimenGet,
156 func() interface{} { return &arvados.GetOptions{} },
157 func(ctx context.Context, opts interface{}) (interface{}, error) {
158 return rtr.fed.SpecimenGet(ctx, *opts.(*arvados.GetOptions))
162 arvados.EndpointSpecimenList,
163 func() interface{} { return &arvados.ListOptions{Limit: -1} },
164 func(ctx context.Context, opts interface{}) (interface{}, error) {
165 return rtr.fed.SpecimenList(ctx, *opts.(*arvados.ListOptions))
169 arvados.EndpointSpecimenDelete,
170 func() interface{} { return &arvados.DeleteOptions{} },
171 func(ctx context.Context, opts interface{}) (interface{}, error) {
172 return rtr.fed.SpecimenDelete(ctx, *opts.(*arvados.DeleteOptions))
177 methods := []string{route.endpoint.Method}
178 if route.endpoint.Method == "PATCH" {
179 methods = append(methods, "PUT")
181 for _, method := range methods {
182 rtr.mux.HandlerFunc(method, "/"+route.endpoint.Path, func(w http.ResponseWriter, req *http.Request) {
183 params, err := rtr.loadRequestParams(req, route.endpoint.AttrsKey)
185 rtr.sendError(w, err)
188 opts := route.defaultOpts()
189 err = rtr.transcode(params, opts)
191 rtr.sendError(w, err)
194 respOpts, err := rtr.responseOptions(opts)
196 rtr.sendError(w, err)
200 creds := auth.CredentialsFromRequest(req)
201 if rt, _ := params["reader_tokens"].([]interface{}); len(rt) > 0 {
202 for _, t := range rt {
203 if t, ok := t.(string); ok {
204 creds.Tokens = append(creds.Tokens, t)
209 ctx = context.WithValue(ctx, auth.ContextKeyCredentials, creds)
210 ctx = arvados.ContextWithRequestID(ctx, req.Header.Get("X-Request-Id"))
211 resp, err := route.exec(ctx, opts)
213 ctxlog.FromContext(ctx).WithError(err).Debugf("returning error response for %#v", err)
214 rtr.sendError(w, err)
217 rtr.sendResponse(w, resp, respOpts)
223 func (rtr *router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
225 if m := r.FormValue("_method"); m != "" {
230 rtr.mux.ServeHTTP(w, r)