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.EndpointCollectionDelete,
68 func() interface{} { return &arvados.DeleteOptions{} },
69 func(ctx context.Context, opts interface{}) (interface{}, error) {
70 return rtr.fed.CollectionDelete(ctx, *opts.(*arvados.DeleteOptions))
74 arvados.EndpointContainerCreate,
75 func() interface{} { return &arvados.CreateOptions{} },
76 func(ctx context.Context, opts interface{}) (interface{}, error) {
77 return rtr.fed.ContainerCreate(ctx, *opts.(*arvados.CreateOptions))
81 arvados.EndpointContainerUpdate,
82 func() interface{} { return &arvados.UpdateOptions{} },
83 func(ctx context.Context, opts interface{}) (interface{}, error) {
84 return rtr.fed.ContainerUpdate(ctx, *opts.(*arvados.UpdateOptions))
88 arvados.EndpointContainerGet,
89 func() interface{} { return &arvados.GetOptions{} },
90 func(ctx context.Context, opts interface{}) (interface{}, error) {
91 return rtr.fed.ContainerGet(ctx, *opts.(*arvados.GetOptions))
95 arvados.EndpointContainerList,
96 func() interface{} { return &arvados.ListOptions{Limit: -1} },
97 func(ctx context.Context, opts interface{}) (interface{}, error) {
98 return rtr.fed.ContainerList(ctx, *opts.(*arvados.ListOptions))
102 arvados.EndpointContainerDelete,
103 func() interface{} { return &arvados.DeleteOptions{} },
104 func(ctx context.Context, opts interface{}) (interface{}, error) {
105 return rtr.fed.ContainerDelete(ctx, *opts.(*arvados.DeleteOptions))
109 arvados.EndpointContainerLock,
111 return &arvados.GetOptions{Select: []string{"uuid", "state", "priority", "auth_uuid", "locked_by_uuid"}}
113 func(ctx context.Context, opts interface{}) (interface{}, error) {
114 return rtr.fed.ContainerLock(ctx, *opts.(*arvados.GetOptions))
118 arvados.EndpointContainerUnlock,
120 return &arvados.GetOptions{Select: []string{"uuid", "state", "priority", "auth_uuid", "locked_by_uuid"}}
122 func(ctx context.Context, opts interface{}) (interface{}, error) {
123 return rtr.fed.ContainerUnlock(ctx, *opts.(*arvados.GetOptions))
127 arvados.EndpointSpecimenCreate,
128 func() interface{} { return &arvados.CreateOptions{} },
129 func(ctx context.Context, opts interface{}) (interface{}, error) {
130 return rtr.fed.SpecimenCreate(ctx, *opts.(*arvados.CreateOptions))
134 arvados.EndpointSpecimenUpdate,
135 func() interface{} { return &arvados.UpdateOptions{} },
136 func(ctx context.Context, opts interface{}) (interface{}, error) {
137 return rtr.fed.SpecimenUpdate(ctx, *opts.(*arvados.UpdateOptions))
141 arvados.EndpointSpecimenGet,
142 func() interface{} { return &arvados.GetOptions{} },
143 func(ctx context.Context, opts interface{}) (interface{}, error) {
144 return rtr.fed.SpecimenGet(ctx, *opts.(*arvados.GetOptions))
148 arvados.EndpointSpecimenList,
149 func() interface{} { return &arvados.ListOptions{Limit: -1} },
150 func(ctx context.Context, opts interface{}) (interface{}, error) {
151 return rtr.fed.SpecimenList(ctx, *opts.(*arvados.ListOptions))
155 arvados.EndpointSpecimenDelete,
156 func() interface{} { return &arvados.DeleteOptions{} },
157 func(ctx context.Context, opts interface{}) (interface{}, error) {
158 return rtr.fed.SpecimenDelete(ctx, *opts.(*arvados.DeleteOptions))
163 methods := []string{route.endpoint.Method}
164 if route.endpoint.Method == "PATCH" {
165 methods = append(methods, "PUT")
167 for _, method := range methods {
168 rtr.mux.HandlerFunc(method, "/"+route.endpoint.Path, func(w http.ResponseWriter, req *http.Request) {
169 params, err := rtr.loadRequestParams(req, route.endpoint.AttrsKey)
171 rtr.sendError(w, err)
174 opts := route.defaultOpts()
175 err = rtr.transcode(params, opts)
177 rtr.sendError(w, err)
180 respOpts, err := rtr.responseOptions(opts)
182 rtr.sendError(w, err)
186 creds := auth.CredentialsFromRequest(req)
188 ctx = context.WithValue(ctx, auth.ContextKeyCredentials, creds)
189 ctx = arvados.ContextWithRequestID(ctx, req.Header.Get("X-Request-Id"))
190 resp, err := route.exec(ctx, opts)
192 ctxlog.FromContext(ctx).WithError(err).Debugf("returning error response for %#v", err)
193 rtr.sendError(w, err)
196 rtr.sendResponse(w, resp, respOpts)
202 func (rtr *router) ServeHTTP(w http.ResponseWriter, r *http.Request) {
204 if m := r.FormValue("_method"); m != "" {
209 rtr.mux.ServeHTTP(w, r)