13497: Add controller, proxy to Rails API.
[arvados.git] / lib / controller / handler.go
1 // Copyright (C) The Arvados Authors. All rights reserved.
2 //
3 // SPDX-License-Identifier: AGPL-3.0
4
5 package controller
6
7 import (
8         "io"
9         "net/http"
10         "net/url"
11         "sync"
12
13         "git.curoverse.com/arvados.git/sdk/go/arvados"
14         "git.curoverse.com/arvados.git/sdk/go/health"
15         "git.curoverse.com/arvados.git/sdk/go/httpserver"
16 )
17
18 type Handler struct {
19         Cluster *arvados.Cluster
20
21         setupOnce    sync.Once
22         mux          http.ServeMux
23         handlerStack http.Handler
24         proxyClient  *arvados.Client
25 }
26
27 func (h *Handler) ServeHTTP(w http.ResponseWriter, req *http.Request) {
28         h.setupOnce.Do(h.setup)
29         h.handlerStack.ServeHTTP(w, req)
30 }
31
32 func (h *Handler) setup() {
33         h.mux.Handle("/_health/", &health.Handler{
34                 Token:  h.Cluster.ManagementToken,
35                 Prefix: "/_health/",
36         })
37         h.mux.Handle("/", http.HandlerFunc(h.proxyRailsAPI))
38         h.handlerStack = httpserver.LogRequests(&h.mux)
39 }
40
41 func (h *Handler) proxyRailsAPI(w http.ResponseWriter, incomingReq *http.Request) {
42         url, err := findRailsAPI(h.Cluster)
43         if err != nil {
44                 http.Error(w, err.Error(), http.StatusInternalServerError)
45                 return
46         }
47         req := *incomingReq
48         req.URL.Host = url.Host
49         resp, err := arvados.InsecureHTTPClient.Do(&req)
50         if err != nil {
51                 http.Error(w, err.Error(), http.StatusInternalServerError)
52                 return
53         }
54         for k, v := range resp.Header {
55                 for _, v := range v {
56                         w.Header().Add(k, v)
57                 }
58         }
59         w.WriteHeader(resp.StatusCode)
60         io.Copy(w, resp.Body)
61 }
62
63 // For now, findRailsAPI always uses the rails API running on this
64 // node.
65 func findRailsAPI(cluster *arvados.Cluster) (*url.URL, error) {
66         node, err := cluster.GetThisSystemNode()
67         if err != nil {
68                 return nil, err
69         }
70         return url.Parse("http://" + node.RailsAPI.Listen)
71 }